paramVal = request.getParameters().get(paramStr);
176 | if (paramVal == null || paramVal.isEmpty()) {
177 | if (paramA.required()) {
178 | throw new IllegalArgumentException("param '" + paramStr + "' required.");
179 | }
180 | if (paramType.isPrimitive()) {
181 | throw new IllegalArgumentException("param '" + paramStr + "' required for primitive type '" + paramType.getName() + "'.");
182 | }
183 | } else {
184 | if (paramType.equals(String.class)) {
185 | // String
186 | if (paramVal.size() > 1) {
187 | throw new IllegalArgumentException("parameter '" + paramStr + "' is a array.");
188 | }
189 | param = paramVal.get(0);
190 |
191 | } else if (paramType.equals(Integer.class) || paramType.equals(int.class)) {
192 | // int
193 | if (paramVal.size() > 1) {
194 | throw new IllegalArgumentException("parameter '" + paramStr + "' is a array.");
195 | }
196 | param = Integer.valueOf(paramVal.get(0));
197 |
198 | } else if (paramType.equals(Long.class) || paramType.equals(long.class)) {
199 | // int
200 | if (paramVal.size() > 1) {
201 | throw new IllegalArgumentException("parameter '" + paramStr + "' is a array.");
202 | }
203 | param = Long.valueOf(paramVal.get(0));
204 |
205 | } else if (paramType.equals(Byte.class) || paramType.equals(byte.class)) {
206 | // int
207 | if (paramVal.size() > 1) {
208 | throw new IllegalArgumentException("parameter '" + paramStr + "' is a array.");
209 | }
210 | param = Byte.valueOf(paramVal.get(0));
211 |
212 | } else if (paramType.equals(Double.class) || paramType.equals(double.class)) {
213 | // int
214 | if (paramVal.size() > 1) {
215 | throw new IllegalArgumentException("parameter '" + paramStr + "' is a array.");
216 | }
217 | param = Double.valueOf(paramVal.get(0));
218 |
219 | } else if (paramType.equals(Float.class) || paramType.equals(float.class)) {
220 | // int
221 | if (paramVal.size() > 1) {
222 | throw new IllegalArgumentException("parameter '" + paramStr + "' is a array.");
223 | }
224 | param = Float.valueOf(paramVal.get(0));
225 |
226 | } else if (paramType.equals(Boolean.class) || paramType.equals(boolean.class)) {
227 | // int
228 | if (paramVal.size() > 1) {
229 | throw new IllegalArgumentException("parameter '" + paramStr + "' is a array.");
230 | }
231 | param = Boolean.valueOf(paramVal.get(0));
232 |
233 | } else if (paramType.isArray()) {
234 | Class> componentType = paramType.getComponentType();
235 | if (componentType.equals(String.class)) {
236 | // String
237 | param = paramVal.toArray(new String[0]);
238 |
239 | } else if (componentType.equals(Integer.class) || componentType.equals(int.class)) {
240 | // int
241 | Object array = Array.newInstance(componentType, paramVal.size());
242 | for (int i1 = 0; i1 < paramVal.size(); i1++) {
243 | Integer it = Integer.valueOf(paramVal.get(i1));
244 | Array.set(array, i1, it);
245 | }
246 | param = array;
247 |
248 | } else if (componentType.equals(Long.class) || componentType.equals(long.class)) {
249 | // long
250 | Object array = Array.newInstance(componentType, paramVal.size());
251 | for (int i1 = 0; i1 < paramVal.size(); i1++) {
252 | Long it = Long.valueOf(paramVal.get(i1));
253 | Array.set(array, i1, it);
254 | }
255 | param = array;
256 |
257 | } else if (componentType.equals(Byte.class) || componentType.equals(byte.class)) {
258 | // Byte
259 | Object array = Array.newInstance(componentType, paramVal.size());
260 | for (int i1 = 0; i1 < paramVal.size(); i1++) {
261 | Byte it = Byte.valueOf(paramVal.get(i1));
262 | Array.set(array, i1, it);
263 | }
264 | param = array;
265 |
266 | } else if (componentType.equals(Double.class) || componentType.equals(double.class)) {
267 | // Double
268 | Object array = Array.newInstance(componentType, paramVal.size());
269 | for (int i1 = 0; i1 < paramVal.size(); i1++) {
270 | Double it = Double.valueOf(paramVal.get(i1));
271 | Array.set(array, i1, it);
272 | }
273 | param = array;
274 |
275 | } else if (componentType.equals(Float.class) || componentType.equals(float.class)) {
276 | // Float
277 | Object array = Array.newInstance(componentType, paramVal.size());
278 | for (int i1 = 0; i1 < paramVal.size(); i1++) {
279 | Float it = Float.valueOf(paramVal.get(i1));
280 | Array.set(array, i1, it);
281 | }
282 | param = array;
283 |
284 | } else if (componentType.equals(Boolean.class) || componentType.equals(boolean.class)) {
285 | // Boolean
286 | Object array = Array.newInstance(componentType, paramVal.size());
287 | for (int i1 = 0; i1 < paramVal.size(); i1++) {
288 | Boolean it = Boolean.valueOf(paramVal.get(i1));
289 | Array.set(array, i1, it);
290 | }
291 | param = array;
292 | }
293 |
294 | } else {
295 | throw new IllegalArgumentException("cannot convert parameter '" + paramStr + "' to '" + paramType.getName() + "'.");
296 | }
297 | }
298 | }
299 | }
300 | }
301 |
302 | paramList.add(param);
303 | }
304 |
305 | Object bean = contxt.getBean(requestMapper.getBeanName());
306 |
307 | return requestMapper.getProxyMethod().invoke(bean, paramList.toArray());
308 | }
309 | }
310 |
--------------------------------------------------------------------------------
/src/main/java/com/xjd/nhs/core/NettyHttpChannelHandler.java:
--------------------------------------------------------------------------------
1 | package com.xjd.nhs.core;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.nio.charset.Charset;
7 | import java.util.*;
8 |
9 | import io.netty.buffer.ByteBuf;
10 | import io.netty.buffer.CompositeByteBuf;
11 | import io.netty.buffer.Unpooled;
12 | import io.netty.channel.ChannelHandlerContext;
13 | import io.netty.channel.SimpleChannelInboundHandler;
14 | import io.netty.handler.codec.http.*;
15 | import io.netty.handler.codec.http.multipart.*;
16 | import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
17 | import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
18 | import io.netty.handler.stream.ChunkedFile;
19 | import io.netty.handler.stream.ChunkedInput;
20 | import io.netty.handler.stream.ChunkedStream;
21 |
22 | import org.perf4j.log4j.Log4JStopWatch;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | import com.fasterxml.jackson.databind.ObjectMapper;
27 | import com.fasterxml.jackson.databind.SerializationFeature;
28 | import com.xjd.nhs.HttpResponse;
29 | import com.xjd.nhs.context.RequestHolder;
30 |
31 | /**
32 | *
33 | * Http请求的业务解析, 线程不安全
34 | *
35 | * @author elvis.xu
36 | * @since 2015-6-4
37 | */
38 | public class NettyHttpChannelHandler extends SimpleChannelInboundHandler {
39 | private static Logger log = LoggerFactory.getLogger(NettyHttpChannelHandler.class);
40 |
41 | protected static ObjectMapper objectMapper = new ObjectMapper();
42 | protected static HttpDataFactory httpDataFactory = new DefaultHttpDataFactory();
43 |
44 | static {
45 | objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
46 | }
47 |
48 | protected HttpRequestRouter router;
49 | protected NettyHttpRequest request;
50 | protected HttpPostRequestDecoder decoder;
51 | protected CompositeByteBuf buf;
52 |
53 | protected boolean reset = false;
54 |
55 | protected Log4JStopWatch stopWatch;
56 |
57 | public NettyHttpChannelHandler(HttpRequestRouter httpRequestRouter) {
58 | if (httpRequestRouter == null) {
59 | throw new RuntimeException("httpRequestRouter cannot be null.");
60 | }
61 | this.router = httpRequestRouter;
62 | }
63 |
64 | @Override
65 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
66 | log.error("netty exception caught: ", cause);
67 | reset();
68 | ctx.close();
69 | }
70 |
71 | @Override
72 | protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
73 | if (msg instanceof HttpRequest) {
74 | startWatch();
75 |
76 | reset = false;
77 |
78 | HttpRequest httpRequest = (HttpRequest) msg;
79 |
80 | request = new NettyHttpRequest(httpRequest);
81 | request.setLocalAddress(ctx.channel().localAddress());
82 | request.setRemoteAddress(ctx.channel().remoteAddress());
83 |
84 | Collection cookies = null;
85 | String cookieStr = request.headers().get(HttpHeaders.Names.COOKIE);
86 | if (cookieStr == null) {
87 | cookies = Collections.emptySet();
88 | } else {
89 | cookies = CookieDecoder.decode(cookieStr);
90 | }
91 |
92 | QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());
93 | request.setRequestUri(queryStringDecoder.path());
94 | Map> params = queryStringDecoder.parameters();
95 | if (httpRequest.getMethod() == HttpMethod.POST) {
96 | Map> ps = new HashMap>();
97 | ps.putAll(params);
98 | request.setParameters(ps);
99 | } else {
100 | request.setParameters(params);
101 | }
102 |
103 | if (httpRequest.getMethod() == HttpMethod.POST) {
104 | request.setMultipart(HttpPostRequestDecoder.isMultipart(httpRequest));
105 | }
106 |
107 | if (request.isMultipart()) {
108 | request.setUploadedFiles(new LinkedList());
109 | } else {
110 | request.setUploadedFiles(Collections. emptyList());
111 | }
112 |
113 | HttpResponse response = router.support(request); // 是否支持该请求的处理
114 |
115 | if (response != null) { // 不支持
116 | write(ctx, request, response);
117 | reset();
118 | return;
119 | }
120 |
121 | if (httpRequest.getMethod() == HttpMethod.POST) {
122 | if (request.isMultipart() || isFormData(request.getHeaders().get(HttpHeaders.Names.CONTENT_TYPE))) {
123 | try {
124 | decoder = new HttpPostRequestDecoder(httpDataFactory, httpRequest);
125 | } catch (ErrorDataDecoderException e) {
126 | log.error("cannot reolve request.", e);
127 | decodeError(ctx, request);
128 | return;
129 | }
130 | }
131 | }
132 |
133 | if (httpRequest.getMethod() == HttpMethod.POST && decoder == null) {// 不需要decoder使用Bytebuf
134 | request.setCustomBody(true);
135 | buf = Unpooled.compositeBuffer(); // 注意大小只有16个
136 | }
137 |
138 | } else if (msg instanceof HttpContent) {
139 | if (reset) {
140 | return;
141 | }
142 | HttpContent chunk = (HttpContent) msg;
143 |
144 | if (decoder != null) {
145 | try {
146 | decoder.offer(chunk);
147 | decodeAttributes(decoder, request);
148 | } catch (ErrorDataDecoderException e) {
149 | log.error("cannot reolve request.", e);
150 | decodeError(ctx, request);
151 | return;
152 | } catch (IOException e) {
153 | log.error("cannot reolve request.", e);
154 | decodeError(ctx, request);
155 | return;
156 | }
157 | } else if (buf != null) { // 不需要decoder
158 | buf.addComponent(chunk.content());
159 | chunk.content().retain();
160 | }
161 |
162 | if (chunk instanceof LastHttpContent) {
163 | if (buf != null && buf.numComponents() > 0) {
164 | int len = 0;
165 | for (int i = 0; i < buf.numComponents(); i++) {
166 | len += buf.component(i).readableBytes();
167 | }
168 | byte[] bs = new byte[len];
169 | len = 0;
170 | for (int i = 0; i < buf.numComponents(); i++) {
171 | int r = buf.component(i).readableBytes();
172 | buf.component(i).readBytes(bs, len, r);
173 | buf.component(i).release();
174 | len += r;
175 | }
176 | request.setBody(bs);
177 | }
178 | RequestHolder.set(request);
179 | HttpResponse response = router.route(request);
180 | RequestHolder.clear();
181 | write(ctx, request, response);
182 | reset(); // 全部完成后reset一下,释放资源
183 | }
184 | }
185 | }
186 |
187 | protected void write(ChannelHandlerContext ctx, NettyHttpRequest request, HttpResponse res) throws Exception {
188 | DefaultHttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), res.getStatus());
189 |
190 | // header
191 | if (res.getHeaders() != null) {
192 | response.headers().set(res.getHeaders());
193 | }
194 |
195 | // keepAlive的判断
196 | if (HttpHeaders.isKeepAlive(request)) {
197 | response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
198 | }
199 |
200 | // cookie
201 | if (res.getCookies() != null && !res.getCookies().isEmpty()) {
202 | String cookie = ClientCookieEncoder.encode(res.getCookies());
203 | response.headers().set(HttpHeaders.Names.SET_COOKIE, cookie);
204 | }
205 |
206 | // 跨域问题
207 | response.headers().set(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
208 | response.headers().set(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, DELETE, HEAD, OPTIONS");
209 | response.headers().set(HttpHeaders.Names.ACCESS_CONTROL_EXPOSE_HEADERS, "Origin, X-Requested-With, Content-Type, Accept");
210 |
211 | // 输出对象
212 | Object rt = res.getContent();
213 | long length = 0;
214 | if (rt == null) {
215 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, 0);
216 | response.headers().remove(HttpHeaders.Names.CONTENT_TYPE);
217 | ctx.write(response);
218 | ctx.write(LastHttpContent.EMPTY_LAST_CONTENT);
219 | } else {
220 | response.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
221 | if (rt instanceof byte[]) {
222 | byte[] bs = (byte[]) rt;
223 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, bs.length);
224 | ctx.write(response);
225 | writeBytes(ctx, bs);
226 |
227 | } else if (rt instanceof String) {
228 | String s = (String) rt;
229 | byte[] bs = (byte[]) s.getBytes(getCharset(response.headers().get(HttpHeaders.Names.CONTENT_TYPE)));
230 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, bs.length);
231 | ctx.write(response);
232 | writeBytes(ctx, bs);
233 |
234 | } else if (rt instanceof InputStream) {
235 | InputStream is = (InputStream) rt;
236 | HttpChunkedInput input = new HttpChunkedInput(new ChunkedStream(is));
237 | ctx.write(response);
238 | ctx.write(input);
239 |
240 | } else if (rt instanceof File) {
241 | File f = (File) rt;
242 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, f.length());
243 | HttpChunkedInput input = new HttpChunkedInput(new ChunkedFile(f));
244 | ctx.write(response);
245 | ctx.write(input);
246 |
247 | } else {
248 | String contentType = response.headers().get(HttpHeaders.Names.CONTENT_TYPE);
249 | if (contentType != null && contentType.toLowerCase().indexOf("json") != -1) { // JSON转换
250 | Charset c = getCharset(contentType);
251 | if (Charset.forName("UTF-8").equals(c)) {
252 | byte[] bs = objectMapper.writeValueAsBytes(rt);
253 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, bs.length);
254 | ctx.write(response);
255 | writeBytes(ctx, bs);
256 | } else {
257 | String s = objectMapper.writeValueAsString(rt);
258 | byte[] bs = (byte[]) s.getBytes(c);
259 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, bs.length);
260 | ctx.write(response);
261 | writeBytes(ctx, bs);
262 | }
263 |
264 | } else if (contentType != null && contentType.toLowerCase().indexOf("xml") != -1) {
265 | // TODO XML转换
266 | } else {
267 | // TODO 默认序列化
268 | }
269 | }
270 | }
271 | log.debug("request process: uri={}, resStatus={}", request.getRequestUri(), response.getStatus());
272 | ctx.flush();
273 | stopWatch(request.getRequestUri());
274 | }
275 |
276 | protected Charset getCharset(String contentType) {
277 | int i;
278 | if (contentType == null || (i = contentType.toLowerCase().indexOf("charset")) == -1
279 | || (i = contentType.indexOf('=', i)) == -1) {
280 | return Charset.forName("UTF-8");
281 | }
282 |
283 | try {
284 | return Charset.forName(contentType.substring(i + 1));
285 | } catch (Exception e) {
286 | log.warn("can not parse charset '{}'.", contentType.substring(i + "charset".length()));
287 | }
288 | return Charset.forName("UTF-8");
289 | }
290 |
291 | protected void writeBytes(ChannelHandlerContext ctx, final byte[] bs) {
292 | HttpChunkedInput input = new HttpChunkedInput(new ChunkedInput() {
293 | boolean read = false;
294 |
295 | @Override
296 | public ByteBuf readChunk(ChannelHandlerContext ctx) throws Exception {
297 | if (read) {
298 | return null;
299 | }
300 | ByteBuf buf = Unpooled.wrappedBuffer(bs);
301 | read = true;
302 | return buf;
303 | }
304 |
305 | @Override
306 | public boolean isEndOfInput() throws Exception {
307 | return read;
308 | }
309 |
310 | @Override
311 | public void close() throws Exception {
312 | read = true;
313 | }
314 | });
315 | ctx.write(input);
316 | }
317 |
318 | protected void reset() {
319 | if (!reset) {
320 | if (decoder != null) {
321 | try {
322 | decoder.destroy();
323 | } catch (Exception e) {
324 | log.warn("", e);
325 | }
326 | decoder = null;
327 | }
328 | if (buf != null) {
329 | buf = null;
330 | }
331 | if (request != null) {
332 | request = null;
333 | }
334 | reset = true;
335 | }
336 | }
337 |
338 | protected void decodeError(ChannelHandlerContext ctx, NettyHttpRequest request) throws Exception {
339 | NettyHttpResponse response = new NettyHttpResponse();
340 | response.setStatus(HttpResponseStatus.BAD_REQUEST);
341 | response.setCookies(request.getCookies());
342 | DefaultHttpHeaders headers = new DefaultHttpHeaders();
343 | headers.set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=utf8");
344 | response.setHeaders(headers);
345 | write(ctx, request, response);
346 | reset();
347 | ctx.channel().close();
348 | }
349 |
350 | protected boolean isFormData(String contentType) {
351 | if (contentType == null || contentType.trim().equals("")) {
352 | return false;
353 | }
354 | if (contentType.toLowerCase().startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
355 | return true;
356 | }
357 | return false;
358 | }
359 |
360 | protected void decodeAttributes(HttpPostRequestDecoder decoder, NettyHttpRequest request) throws IOException {
361 | try {
362 | while (decoder.hasNext()) {
363 | InterfaceHttpData interfaceHttpData = decoder.next();
364 | if (interfaceHttpData.getHttpDataType() == HttpDataType.Attribute) {
365 | Attribute attribute = (Attribute) interfaceHttpData;
366 | String name = attribute.getName();
367 | String value = attribute.getValue();
368 |
369 | List attrValues = request.getParameters().get(name);
370 | if (attrValues == null) {
371 | attrValues = new LinkedList();
372 | request.getParameters().put(name, attrValues);
373 | }
374 | attrValues.add(value);
375 |
376 | } else if (interfaceHttpData.getHttpDataType() == HttpDataType.FileUpload) {
377 | FileUpload fileUpload = (FileUpload) interfaceHttpData;
378 |
379 | request.getUploadedFiles().add(fileUpload);
380 | }
381 | }
382 | } catch (HttpPostRequestDecoder.EndOfDataDecoderException e) {
383 | log.debug("{} occured: {}", "EndOfDataDecoderException", e);
384 | }
385 | }
386 |
387 | protected void startWatch() {
388 | stopWatch = new Log4JStopWatch();
389 | }
390 |
391 | protected void stopWatch(String tag) {
392 | if (stopWatch != null) {
393 | stopWatch.stop(tag);
394 | stopWatch = null;
395 | }
396 | }
397 | }
398 |
--------------------------------------------------------------------------------
/src/main/java/com/xjd/nhs/core/NettyHttpRequest.java:
--------------------------------------------------------------------------------
1 | package com.xjd.nhs.core;
2 |
3 | import io.netty.handler.codec.DecoderResult;
4 | import io.netty.handler.codec.http.Cookie;
5 | import io.netty.handler.codec.http.HttpHeaders;
6 | import io.netty.handler.codec.http.HttpMethod;
7 | import io.netty.handler.codec.http.HttpRequest;
8 | import io.netty.handler.codec.http.HttpVersion;
9 | import io.netty.handler.codec.http.multipart.FileUpload;
10 |
11 | import java.net.SocketAddress;
12 | import java.util.Collection;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | public class NettyHttpRequest implements com.xjd.nhs.HttpRequest, HttpRequest {
17 |
18 | protected HttpRequest request;
19 |
20 | protected SocketAddress remoteAddress;
21 | protected SocketAddress localAddress;
22 | protected String requestUri;
23 | protected Map> parameters;
24 | protected Collection cookies;
25 | protected boolean multipart;
26 | protected List uploadedFiles;
27 | protected boolean customBody;
28 | protected byte[] body;
29 |
30 | public NettyHttpRequest(HttpRequest httpRequest) {
31 | this.request = httpRequest;
32 | }
33 |
34 | @Override
35 | public HttpRequest setProtocolVersion(HttpVersion version) {
36 | request.setProtocolVersion(version);
37 | return this;
38 | }
39 |
40 | @Override
41 | public HttpRequest setMethod(HttpMethod method) {
42 | request.setMethod(method);
43 | return this;
44 | }
45 |
46 | @Override
47 | public HttpRequest setUri(String uri) {
48 | request.setUri(uri);
49 | return this;
50 | }
51 |
52 | @Override
53 | public HttpVersion getProtocolVersion() {
54 | return request.getProtocolVersion();
55 | }
56 |
57 | @Override
58 | public HttpHeaders headers() {
59 | return request.headers();
60 | }
61 |
62 | @Override
63 | public DecoderResult getDecoderResult() {
64 | return request.getDecoderResult();
65 | }
66 |
67 | @Override
68 | public void setDecoderResult(DecoderResult result) {
69 | request.setDecoderResult(result);
70 | }
71 |
72 | public SocketAddress getRemoteAddress() {
73 | return remoteAddress;
74 | }
75 |
76 | public SocketAddress getLocalAddress() {
77 | return localAddress;
78 | }
79 |
80 | public String getUri() {
81 | return request.getUri();
82 | }
83 |
84 | public HttpVersion getProtocol() {
85 | return request.getProtocolVersion();
86 | }
87 |
88 | public HttpMethod getMethod() {
89 | return request.getMethod();
90 | }
91 |
92 | public HttpHeaders getHeaders() {
93 | return request.headers();
94 | }
95 |
96 | public Map> getParameters() {
97 | return parameters;
98 | }
99 |
100 | public Collection getCookies() {
101 | return cookies;
102 | }
103 |
104 | public boolean isMultipart() {
105 | return multipart;
106 | }
107 |
108 | public List getUploadedFiles() {
109 | return uploadedFiles;
110 | }
111 |
112 | public void setRemoteAddress(SocketAddress remoteAddress) {
113 | this.remoteAddress = remoteAddress;
114 | }
115 |
116 | public void setLocalAddress(SocketAddress localAddress) {
117 | this.localAddress = localAddress;
118 | }
119 |
120 | public void setParameters(Map> parameters) {
121 | this.parameters = parameters;
122 | }
123 |
124 | public void setCookies(Collection cookies) {
125 | this.cookies = cookies;
126 | }
127 |
128 | public void setMultipart(boolean multipart) {
129 | this.multipart = multipart;
130 | }
131 |
132 | public void setUploadedFiles(List uploadedFiles) {
133 | this.uploadedFiles = uploadedFiles;
134 | }
135 |
136 | public boolean isCustomBody() {
137 | return customBody;
138 | }
139 |
140 | public void setCustomBody(boolean customBody) {
141 | this.customBody = customBody;
142 | }
143 |
144 | public byte[] getBody() {
145 | return body;
146 | }
147 |
148 | public void setBody(byte[] body) {
149 | this.body = body;
150 | }
151 |
152 | @Override
153 | public String getRequestUri() {
154 | return requestUri;
155 | }
156 |
157 | public void setRequestUri(String requestUri) {
158 | this.requestUri = requestUri;
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/com/xjd/nhs/core/NettyHttpResponse.java:
--------------------------------------------------------------------------------
1 | package com.xjd.nhs.core;
2 |
3 | import io.netty.handler.codec.http.Cookie;
4 | import io.netty.handler.codec.http.HttpHeaders;
5 | import io.netty.handler.codec.http.HttpResponseStatus;
6 |
7 | import java.util.Collection;
8 |
9 | import com.xjd.nhs.HttpResponse;
10 |
11 | public class NettyHttpResponse implements HttpResponse {
12 |
13 | protected HttpResponseStatus status;
14 | protected HttpHeaders headers;
15 | protected Collection cookies;
16 | protected Object content;
17 |
18 | public HttpResponseStatus getStatus() {
19 | return status;
20 | }
21 |
22 | public void setStatus(HttpResponseStatus status) {
23 | this.status = status;
24 | }
25 |
26 | public HttpHeaders getHeaders() {
27 | return headers;
28 | }
29 |
30 | public void setHeaders(HttpHeaders headers) {
31 | this.headers = headers;
32 | }
33 |
34 | public Collection getCookies() {
35 | return cookies;
36 | }
37 |
38 | public void setCookies(Collection cookies) {
39 | this.cookies = cookies;
40 | }
41 |
42 | public Object getContent() {
43 | return content;
44 | }
45 |
46 | public void setContent(Object content) {
47 | this.content = content;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/xjd/nhs/core/RequestMapper.java:
--------------------------------------------------------------------------------
1 | package com.xjd.nhs.core;
2 |
3 | import java.lang.reflect.Method;
4 | import java.nio.charset.Charset;
5 | import java.util.Arrays;
6 |
7 | public class RequestMapper {
8 | private String[] reqUris;
9 | private String reqMethod;
10 | private boolean reqSupportMultipart;
11 | private String resContentType;
12 | private Charset resCharset;
13 | private String beanName;
14 | private Method method;
15 | private Method proxyMethod;
16 |
17 | public String[] getReqUris() {
18 | return reqUris;
19 | }
20 |
21 | public void setReqUris(String[] reqUris) {
22 | this.reqUris = reqUris;
23 | }
24 |
25 | public String getReqMethod() {
26 | return reqMethod;
27 | }
28 |
29 | public void setReqMethod(String reqMethod) {
30 | this.reqMethod = reqMethod;
31 | }
32 |
33 | public boolean isReqSupportMultipart() {
34 | return reqSupportMultipart;
35 | }
36 |
37 | public void setReqSupportMultipart(boolean reqSupportMultipart) {
38 | this.reqSupportMultipart = reqSupportMultipart;
39 | }
40 |
41 | public String getResContentType() {
42 | return resContentType;
43 | }
44 |
45 | public void setResContentType(String resContentType) {
46 | this.resContentType = resContentType;
47 | }
48 |
49 | public Charset getResCharset() {
50 | return resCharset;
51 | }
52 |
53 | public void setResCharset(Charset resCharset) {
54 | this.resCharset = resCharset;
55 | }
56 |
57 | public String getBeanName() {
58 | return beanName;
59 | }
60 |
61 | public void setBeanName(String beanName) {
62 | this.beanName = beanName;
63 | }
64 |
65 | public Method getMethod() {
66 | return method;
67 | }
68 |
69 | public void setMethod(Method method) {
70 | this.method = method;
71 | }
72 |
73 | public Method getProxyMethod() {
74 | return proxyMethod;
75 | }
76 |
77 | public void setProxyMethod(Method proxyMethod) {
78 | this.proxyMethod = proxyMethod;
79 | }
80 |
81 | @Override
82 | public String toString() {
83 | return "RequestMapper{" +
84 | "reqUris=" + Arrays.toString(reqUris) +
85 | ", reqMethod='" + reqMethod + '\'' +
86 | ", reqSupportMultipart=" + reqSupportMultipart +
87 | ", resContentType='" + resContentType + '\'' +
88 | ", resCharset=" + resCharset +
89 | ", beanName='" + beanName + '\'' +
90 | ", method='" + (method == null ? method : method.getName()) + '\'' +
91 | ", proxyed=" + (proxyMethod == method ? false : true) +
92 | '}';
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/xjd/nhs/core/ServerConfig.java:
--------------------------------------------------------------------------------
1 | package com.xjd.nhs.core;
2 |
3 | import io.netty.bootstrap.ServerBootstrap;
4 | import io.netty.channel.ChannelInitializer;
5 | import io.netty.channel.ChannelOption;
6 | import io.netty.channel.ChannelPipeline;
7 | import io.netty.channel.EventLoopGroup;
8 | import io.netty.channel.SimpleChannelInboundHandler;
9 | import io.netty.channel.nio.NioEventLoopGroup;
10 | import io.netty.channel.socket.SocketChannel;
11 | import io.netty.channel.socket.nio.NioServerSocketChannel;
12 | import io.netty.handler.codec.http.HttpContentCompressor;
13 | import io.netty.handler.codec.http.HttpRequestDecoder;
14 | import io.netty.handler.codec.http.HttpResponseEncoder;
15 | import io.netty.handler.logging.LogLevel;
16 | import io.netty.handler.logging.LoggingHandler;
17 | import io.netty.handler.stream.ChunkedWriteHandler;
18 | import io.netty.util.internal.logging.InternalLoggerFactory;
19 | import io.netty.util.internal.logging.Slf4JLoggerFactory;
20 |
21 | import java.lang.reflect.Method;
22 | import java.lang.reflect.Modifier;
23 | import java.nio.charset.Charset;
24 | import java.util.HashMap;
25 | import java.util.LinkedList;
26 | import java.util.List;
27 | import java.util.Map;
28 |
29 | import javax.annotation.Resource;
30 |
31 | import org.slf4j.Logger;
32 | import org.slf4j.LoggerFactory;
33 | import org.springframework.aop.support.AopUtils;
34 | import org.springframework.context.ApplicationContext;
35 | import org.springframework.context.annotation.Bean;
36 | import org.springframework.context.annotation.Configuration;
37 | import org.springframework.context.annotation.Scope;
38 | import org.springframework.stereotype.Controller;
39 |
40 | import com.xjd.nhs.annotation.RequestMapping;
41 | import com.xjd.nhs.annotation.ResponseBody;
42 |
43 | @Configuration
44 | public class ServerConfig {
45 | private static Logger log = LoggerFactory.getLogger(ServerConfig.class);
46 |
47 | @Bean
48 | @Resource(name = "channelInitializer")
49 | public ServerBootstrap serverBootstrapFactory(ChannelInitializer channelInitializer) {
50 | // 配置服务器
51 | EventLoopGroup bossGroup = new NioEventLoopGroup();
52 | EventLoopGroup workerGroup = new NioEventLoopGroup();
53 | InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory());
54 | ServerBootstrap serverBootstrap = new ServerBootstrap();
55 | serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
56 | .handler(new LoggingHandler(LogLevel.INFO)).childHandler(channelInitializer)
57 | .option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
58 |
59 | return serverBootstrap;
60 | }
61 |
62 | @Bean(name = "channelInitializer")
63 | public ChannelInitializer initializerFactory(final ApplicationContext contxt) {
64 | return new ChannelInitializer() {
65 | @Override
66 | public void initChannel(SocketChannel ch) throws Exception {
67 | SimpleChannelInboundHandler> channelInboundHandler = contxt.getBean(NettyHttpChannelHandler.class);
68 | ChannelPipeline pipeline = ch.pipeline();
69 | // HTTP
70 | pipeline.addLast(new HttpRequestDecoder());
71 | pipeline.addLast(new HttpResponseEncoder());
72 | pipeline.addLast(new HttpContentCompressor());
73 | pipeline.addLast(new ChunkedWriteHandler());
74 | // 设置处理的Handler
75 | pipeline.addLast(channelInboundHandler);
76 | }
77 | };
78 | }
79 |
80 | @Bean
81 | @Scope("prototype")
82 | @Resource(name = "httpRequestRouter")
83 | public NettyHttpChannelHandler channelHandlerFactory(HttpRequestRouter httpRequestRouter) {
84 | return new NettyHttpChannelHandler(httpRequestRouter);
85 | }
86 |
87 | @Bean(name = "httpRequestRouter")
88 | public HttpRequestRouter routerFactory(ApplicationContext contxt) {
89 | return new HttpRequestRouter(contxt, mapRequest(contxt));
90 | }
91 |
92 | @Bean()
93 | public Map mapRequest(ApplicationContext contxt) {
94 | String[] names = contxt.getBeanNamesForAnnotation(Controller.class);
95 | Map reqMap = new HashMap(names == null ? 0 : names.length);
96 |
97 | for (String name : names) {
98 | Class> clazz;
99 | Object bean = contxt.getBean(name);
100 | boolean proxy = AopUtils.isAopProxy(bean);
101 | if (proxy) {
102 | clazz = AopUtils.getTargetClass(bean);
103 | } else {
104 | clazz = contxt.getType(name);
105 | }
106 |
107 | List methodList = new LinkedList();
108 | for (Method method : clazz.getDeclaredMethods()) {
109 | if (Modifier.isPublic(method.getModifiers())) {
110 | methodList.add(method);
111 | }
112 | }
113 |
114 | RequestMapping rmClazz = clazz.getAnnotation(RequestMapping.class);
115 | if (rmClazz != null && methodList.size() > 1) {
116 | for (Method method : methodList) {
117 | if (method.getAnnotation(RequestMapping.class) == null) {
118 | throw new IllegalArgumentException("cannot mapping ctrl method: " + clazz.getName() + "."
119 | + method.getName() + "()");
120 | }
121 | }
122 | }
123 |
124 | String[] defaultUris = new String[] { "" };
125 | for (Method method : methodList) {
126 | RequestMapping rmMethod = method.getAnnotation(RequestMapping.class);
127 |
128 | if (rmClazz == null && rmMethod == null) {
129 | continue;
130 | }
131 |
132 | RequestMapper reqMapper = new RequestMapper();
133 | reqMapper.setBeanName(name);
134 | reqMapper.setMethod(method);
135 | if (proxy) {
136 | reqMapper.setProxyMethod(AopUtils.getMostSpecificMethod(method, bean.getClass()));
137 | } else {
138 | reqMapper.setProxyMethod(method);
139 | }
140 | {
141 | List uriList = new LinkedList();
142 | String[] clazzUris = (rmClazz == null || rmClazz.value() == null || rmClazz.value().length == 0) ? defaultUris
143 | : rmClazz.value();
144 | String[] methodUris = (rmMethod == null || rmMethod.value() == null || rmMethod.value().length == 0) ? defaultUris
145 | : rmMethod.value();
146 | for (String cu : clazzUris) {
147 | for (String mu : methodUris) {
148 | uriList.add((cu + mu).trim());
149 | }
150 | }
151 | reqMapper.setReqUris(uriList.toArray(new String[uriList.size()]));
152 | }
153 | reqMapper.setReqMethod(rmMethod != null ? rmMethod.method().getCode() : rmClazz.method().getCode());
154 | reqMapper.setReqSupportMultipart(rmMethod != null ? rmMethod.supportMultipart() : rmClazz.supportMultipart());
155 |
156 | ResponseBody rbMethod = method.getAnnotation(ResponseBody.class);
157 | reqMapper.setResContentType(rbMethod != null ? rbMethod.produce().getVal()
158 | : ResponseBody.Produce.APPLICATION_JSON.getVal());
159 | reqMapper.setResCharset(rbMethod != null ? Charset.forName(rbMethod.charset()) : Charset.forName("UTF-8"));
160 |
161 | for (String uri : reqMapper.getReqUris()) {
162 | if (reqMap.get(uri) != null) {
163 | throw new IllegalArgumentException("double mapping uri: " + uri);
164 | }
165 | reqMap.put(uri, reqMapper);
166 | }
167 |
168 | log.debug("map request: {}", reqMapper);
169 | }
170 | }
171 |
172 | return reqMap;
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/src/test/java/Example.java:
--------------------------------------------------------------------------------
1 | import io.netty.bootstrap.ServerBootstrap;
2 | import io.netty.channel.ChannelFuture;
3 |
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.context.ApplicationContext;
7 | import org.springframework.context.support.ClassPathXmlApplicationContext;
8 |
9 | public class Example {
10 | private static Logger log = LoggerFactory.getLogger(Example.class);
11 | public static void main(String[] args) throws Exception {
12 | ApplicationContext contxt = new ClassPathXmlApplicationContext("classpath:spring-test.xml");
13 | ServerBootstrap bootstrap = contxt.getBean(ServerBootstrap.class);
14 | try {
15 | int port = 8095;
16 | ChannelFuture channelFuture = bootstrap.bind(port).sync();
17 | log.info("server start at '{}'...", port);
18 | channelFuture.channel().closeFuture().sync();
19 | } finally {
20 | bootstrap.childGroup().shutdownGracefully();
21 | bootstrap.group().shutdownGracefully();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/java/NettyTest.java:
--------------------------------------------------------------------------------
1 | import java.util.*;
2 | import java.util.Map.Entry;
3 |
4 | import io.netty.bootstrap.ServerBootstrap;
5 | import io.netty.channel.*;
6 | import io.netty.channel.nio.NioEventLoopGroup;
7 | import io.netty.channel.socket.SocketChannel;
8 | import io.netty.channel.socket.nio.NioServerSocketChannel;
9 | import io.netty.handler.codec.http.*;
10 | import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
11 | import io.netty.handler.codec.http.multipart.HttpDataFactory;
12 | import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
13 | import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
14 | import io.netty.handler.stream.ChunkedWriteHandler;
15 |
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 |
19 | public class NettyTest {
20 | private static Logger log = LoggerFactory.getLogger(NettyTest.class);
21 |
22 | public static void main(String[] args) throws Exception {
23 | EventLoopGroup bossGroup = new NioEventLoopGroup();
24 | EventLoopGroup workGroup = new NioEventLoopGroup();
25 |
26 | try {
27 | ServerBootstrap sb = new ServerBootstrap();
28 | sb.group(bossGroup, workGroup).channel(NioServerSocketChannel.class).childHandler(new HttpChannelInitializer());
29 |
30 | Channel channel = sb.bind(8095).sync().channel();
31 |
32 | log.info("server started at: 8095");
33 |
34 | channel.closeFuture().sync();
35 | } finally {
36 | bossGroup.shutdownGracefully();
37 | workGroup.shutdownGracefully();
38 | }
39 | }
40 |
41 | public static class HttpChannelInitializer extends ChannelInitializer {
42 |
43 | protected void initChannel(SocketChannel ch) throws Exception {
44 | ChannelPipeline pipeline = ch.pipeline();
45 |
46 | pipeline.addLast("httpRequestDecoder", new HttpRequestDecoder());
47 | pipeline.addLast("httpResponseEncoder", new HttpResponseEncoder());
48 | pipeline.addLast("httpContentCompressor", new HttpContentCompressor());
49 | pipeline.addLast("chunkedWriteHandler", new ChunkedWriteHandler());
50 | pipeline.addLast("httpHandler", new HttpHandler());
51 | }
52 |
53 | }
54 |
55 | public static class HttpHandler extends SimpleChannelInboundHandler {
56 |
57 | protected HttpPostRequestDecoder httpPostRequestDecoder;
58 |
59 | @Override
60 | public void channelInactive(ChannelHandlerContext ctx) throws Exception {
61 | if (httpPostRequestDecoder != null) {
62 | try {
63 | httpPostRequestDecoder.cleanFiles();
64 | httpPostRequestDecoder = null;
65 | } catch (Exception e) {
66 | log.warn("", e);
67 | }
68 | }
69 | }
70 |
71 | @Override
72 | protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
73 | log.trace("messaage received: {}", msg.getClass().getName());
74 |
75 | if (msg instanceof HttpRequest) {
76 | HttpRequest httpRequest = (HttpRequest) msg;
77 |
78 | log.trace("uri: {}", httpRequest.getUri());
79 | log.trace("protocol: {}", httpRequest.getProtocolVersion().toString());
80 | log.trace("method: {}", httpRequest.getMethod().toString());
81 | log.trace("decoderResult: {}", httpRequest.getDecoderResult().toString());
82 | log.trace("remoteAddress: {}", ctx.channel().remoteAddress());
83 | log.trace("localAddress: {}", ctx.channel().localAddress());
84 |
85 | log.trace("[[headers]]");
86 | HttpHeaders headers = httpRequest.headers();
87 | for (Entry header : headers.entries()) {
88 | log.trace("{}:{}", header.getKey(), header.getValue());
89 | }
90 |
91 | log.trace("[[cookies]]");
92 | Set cookies = null;
93 | String cookieStr = headers.get(HttpHeaders.Names.COOKIE);
94 | if (cookieStr == null) {
95 | cookies = Collections.emptySet();
96 | } else {
97 | cookies = CookieDecoder.decode(cookieStr);
98 | }
99 | for (Cookie cookie : cookies) {
100 | log.trace("Cookie: {}", cookie.toString());
101 | }
102 |
103 | log.trace("[[parameters]]");
104 | QueryStringDecoder queryStringDecoder = new QueryStringDecoder(httpRequest.getUri());
105 | log.trace("uri: {}", queryStringDecoder.uri());
106 | log.trace("path: {}", queryStringDecoder.path());
107 | Map> params = queryStringDecoder.parameters();
108 | for (Entry> entry : params.entrySet()) {
109 | log.trace("{}:{}", entry.getKey(), Arrays.toString(entry.getValue().toArray()));
110 | }
111 |
112 | if (httpRequest.getMethod() == HttpMethod.POST) {
113 | log.trace("isChunked: {}", HttpHeaders.isTransferEncodingChunked(httpRequest));
114 | log.trace("isMulti: {}", HttpPostRequestDecoder.isMultipart(httpRequest));
115 |
116 | HttpDataFactory httpDataFactory;
117 | if (HttpPostRequestDecoder.isMultipart(httpRequest)) {
118 | httpDataFactory = new DefaultHttpDataFactory(true); // use disk
119 | } else {
120 | httpDataFactory = new DefaultHttpDataFactory(); // use mixed
121 | }
122 | try {
123 | httpPostRequestDecoder = new HttpPostRequestDecoder(httpDataFactory, httpRequest);
124 | } catch (ErrorDataDecoderException e) {
125 | log.error("cannot reolve request.");
126 | resolveError(ctx);
127 | return;
128 | }
129 | }
130 |
131 | } else if (msg instanceof HttpContent) {
132 | HttpContent chunk = (HttpContent) msg;
133 | // try {
134 | // httpPostRequestDecoder.offer(chunk);
135 | // } catch (ErrorDataDecoderException e) {
136 | // log.error("cannot reolve request.");
137 | // resolveError(ctx);
138 | // return;
139 | // }
140 |
141 | // log.trace("[[DATA]]");
142 | // while (httpPostRequestDecoder.hasNext()) {
143 | // InterfaceHttpData interfaceHttpData = httpPostRequestDecoder.next();
144 | // if (interfaceHttpData.getHttpDataType() == HttpDataType.Attribute) {
145 | // Attribute attribute = (Attribute) interfaceHttpData;
146 | // log.trace("attribute: {}", attribute.toString());
147 | // } else if (interfaceHttpData.getHttpDataType() == HttpDataType.FileUpload) {
148 | // FileUpload fileUpload = (FileUpload) interfaceHttpData;
149 | // log.trace("fileupload: {}", fileUpload.toString());
150 | // }
151 | // }
152 |
153 | if (chunk instanceof LastHttpContent) {
154 | log.trace("OK");
155 | // 应答
156 | // 应答完成后
157 | // DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
158 | // response.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
159 | // ctx.write(response);
160 | // HttpChunkedInput httpChunkWriter;
161 | // try {
162 | // httpChunkWriter = new HttpChunkedInput(new ChunkedFile(new File("/tmp/tmp.txt")));
163 | // ctx.write(httpChunkWriter, ctx.newProgressivePromise()).addListener(
164 | // new ChannelProgressiveFutureListener() {
165 | //
166 | // @Override
167 | // public void operationComplete(ChannelProgressiveFuture future) throws Exception {
168 | // System.out.println("FINISH!");
169 | // }
170 | //
171 | // @Override
172 | // public void operationProgressed(ChannelProgressiveFuture future, long progress, long total)
173 | // throws Exception {
174 | // System.out.println(progress + ":" + total);
175 | // }
176 | //
177 | // });
178 | //
179 | // } catch (IOException e) {
180 | // e.printStackTrace();
181 | // }
182 | // ctx.write(new
183 | // DefaultHttpContent(Unpooled.wrappedBuffer("HELLO".getBytes(Charset.forName("utf8")))));
184 | // ctx.write(LastHttpContent.EMPTY_LAST_CONTENT);
185 | DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
186 | // response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/json; charset=UTF-8");
187 | response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, 0);
188 | response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
189 | response.headers().set(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
190 | response.headers().set(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, DELETE, HEAD, OPTIONS");
191 | response.headers().set(HttpHeaders.Names.ACCESS_CONTROL_EXPOSE_HEADERS, "Origin, X-Requested-With, Content-Type, Accept");
192 | ctx.write(response);
193 | ctx.write(LastHttpContent.EMPTY_LAST_CONTENT);
194 | ctx.flush();
195 | // reset();
196 | }
197 | }
198 | }
199 |
200 | protected void resolveError(ChannelHandlerContext ctx) {
201 | // 返回错误
202 | reset();
203 | ctx.channel().close();
204 | }
205 |
206 | protected void reset() {
207 | if (httpPostRequestDecoder != null) {
208 | try {
209 | httpPostRequestDecoder.destroy();
210 | httpPostRequestDecoder = null;
211 | } catch (Exception e) {
212 | log.warn("", e);
213 | }
214 | }
215 | }
216 | }
217 |
218 | }
219 |
--------------------------------------------------------------------------------
/src/test/java/controller/TestCtrl.java:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | import org.springframework.stereotype.Controller;
7 |
8 | import com.xjd.nhs.HttpRequest;
9 | import com.xjd.nhs.annotation.RequestBody;
10 | import com.xjd.nhs.annotation.RequestMapping;
11 |
12 | /**
13 | * @author elvis.xu
14 | * @since 2015-08-27 22:43
15 | */
16 | @Controller
17 | @RequestMapping(value = "/api/10")
18 | public class TestCtrl {
19 |
20 | @RequestMapping(value = "/test1")
21 | public Object test1(@RequestBody Test1Req test1) {
22 | return test1;
23 | }
24 |
25 | @RequestMapping(value = "/test2", supportMultipart = true)
26 | public Object test2(HttpRequest request) {
27 | try {
28 | request.getUploadedFiles().get(0).renameTo(new File("D:/tmp/tmp.jpg"));
29 | } catch (IOException e) {
30 | e.printStackTrace();
31 | }
32 | return "OK";
33 | }
34 |
35 | public static class Test1Req {
36 | private String name;
37 | private Integer age;
38 |
39 | public String getName() {
40 | return name;
41 | }
42 |
43 | public void setName(String name) {
44 | this.name = name;
45 | }
46 |
47 | public Integer getAge() {
48 | return age;
49 | }
50 |
51 | public void setAge(Integer age) {
52 | this.age = age;
53 | }
54 |
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/controller/TestCtrl11.java:
--------------------------------------------------------------------------------
1 | package controller;
2 |
3 | import java.io.IOException;
4 | import java.util.Arrays;
5 |
6 | import io.netty.handler.codec.http.multipart.FileUpload;
7 |
8 | import org.springframework.stereotype.Controller;
9 |
10 | import com.xjd.nhs.annotation.RequestMapping;
11 | import com.xjd.nhs.annotation.RequestParam;
12 |
13 | /**
14 | * @author elvis.xu
15 | * @since 2015-10-20 23:42
16 | */
17 | @Controller
18 | @RequestMapping(value = "/api/11")
19 | public class TestCtrl11 {
20 | @RequestMapping(value = "/test1")
21 | public Object test1(@RequestParam(value = "name", required = true) String name, @RequestParam("age") Integer age, @RequestParam("isgood") boolean isgood) {
22 | System.out.println(name + ", " + age + ", " + isgood);
23 | return "OK";
24 | }
25 |
26 | @RequestMapping(value = "/test2")
27 | public Object test2(@RequestParam(value = "name", required = true) String[] name, @RequestParam("age") Integer[] age, @RequestParam("isgood") boolean[] isgood) {
28 | System.out.println(Arrays.toString(name) + ", " + Arrays.toString(age) + ", " + Arrays.toString(isgood));
29 | return "OK";
30 | }
31 |
32 | @RequestMapping(value = "/test3", supportMultipart = true)
33 | public Object test3(@RequestParam(value = "name") String[] name, @RequestParam("age") Integer[] age, @RequestParam("isgood") boolean[] isgood,
34 | @RequestParam("file") FileUpload fu) throws IOException {
35 | System.out.println(Arrays.toString(name) + ", " + Arrays.toString(age) + ", " + Arrays.toString(isgood));
36 |
37 | try {
38 | System.out.println(fu.getName() + ", " + fu.getFilename() + ", " + fu.getContentType() + ": " + fu.getString());
39 | } catch (Exception e) {
40 | e.printStackTrace();
41 | }
42 | return "OK";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/test/resources/log4j2-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | %d{HH:mm:ss.SSS} [%t] %5level %logger{36}(%L) - %msg%n
9 |
10 |
11 |
12 |
13 | %d{HH:mm:ss.SSS} [%t] %5level %logger{36}(%L) - %msg%n
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/test/resources/spring-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------