├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── api
│ │ └── mengkang
│ │ └── net
│ │ ├── Config.java
│ │ ├── ErrorCode.java
│ │ ├── Request.java
│ │ ├── RequestHandler.java
│ │ ├── Response.java
│ │ ├── api
│ │ ├── BaseController.java
│ │ └── UserController.java
│ │ ├── dao
│ │ └── UserDao.java
│ │ ├── entity
│ │ └── User.java
│ │ ├── model
│ │ └── UserModel.java
│ │ ├── netty
│ │ ├── HttpServer.java
│ │ ├── HttpServerHandler.java
│ │ └── HttpServerInitializer.java
│ │ └── utils
│ │ └── mysql
│ │ ├── DMLTypes.java
│ │ ├── DbFiled.java
│ │ ├── JdbcPool.java
│ │ ├── MySelect.java
│ │ └── Mysql.java
└── resources
│ ├── api.properties
│ ├── read.db.properties
│ └── write.db.properties
└── test
└── java
└── TestUserInfo.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /demo.iml
2 | /target
3 | /.idea
4 | /netty-http-demo.iml
5 | # Created by .ignore support plugin (hsz.mobi)
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # netty-http-demo
2 | 直播 https://segmentfault.com/l/1500000009988553
3 | 详细讲解 https://segmentfault.com/a/1190000010333464
4 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | mengkang.net
8 | demo
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | io.netty
14 | netty-all
15 | 5.0.0.Alpha2
16 |
17 |
18 | junit
19 | junit
20 | 4.7
21 | test
22 |
23 |
24 | com.alibaba
25 | fastjson
26 | 1.2.27
27 |
28 |
29 | ch.qos.logback
30 | logback-classic
31 | 1.1.3
32 |
33 |
34 |
35 | mysql
36 | mysql-connector-java
37 | 5.1.18
38 |
39 |
40 | commons-dbcp
41 | commons-dbcp
42 | 1.4
43 |
44 |
45 | commons-pool
46 | commons-pool
47 | 1.6
48 |
49 |
50 |
51 |
52 |
53 |
54 | org.apache.maven.plugins
55 | maven-compiler-plugin
56 | 2.3.2
57 |
58 | 1.8
59 | 1.8
60 | UTF-8
61 |
62 |
63 |
64 | org.apache.maven.plugins
65 | maven-dependency-plugin
66 | 2.1
67 |
68 |
69 | copy-dependencies
70 | compile
71 |
72 | copy-dependencies
73 |
74 |
75 | ${project.build.directory}/lib
76 | false
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/Config.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStreamReader;
5 | import java.util.Properties;
6 |
7 | /**
8 | * @author zhoumengkang
9 | */
10 | public class Config {
11 |
12 | private static Properties PROPERTIES = new Properties();
13 | private static final String CONFIG_NAME = "/api.properties";
14 | private static Config instance;
15 |
16 | private Config() {
17 | try {
18 | PROPERTIES.load(new InputStreamReader(getClass().getResourceAsStream(CONFIG_NAME), "UTF-8"));
19 | } catch (IOException e) {
20 | e.printStackTrace();
21 | }
22 | }
23 |
24 | private synchronized static Config getInstance() {
25 | if (null == instance) {
26 | instance = new Config();
27 | }
28 | return instance;
29 | }
30 |
31 | public static int getInt(String str) {
32 | try {
33 | if (null == instance) {
34 | getInstance();
35 | }
36 | return Integer.parseInt(PROPERTIES.getProperty(str));
37 | } catch (Exception e) {
38 | e.printStackTrace();
39 | return 0;
40 | }
41 | }
42 |
43 | public static long getLong(String str) {
44 | try {
45 | if (null == instance) {
46 | getInstance();
47 | }
48 | return Long.parseLong(PROPERTIES.getProperty(str));
49 | } catch (Exception e) {
50 | e.printStackTrace();
51 | return 0;
52 | }
53 | }
54 |
55 | public static double getDouble(String str) {
56 | try {
57 | if (null == instance) {
58 | getInstance();
59 | }
60 | return Double.parseDouble(PROPERTIES.getProperty(str));
61 |
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | return 0;
65 | }
66 | }
67 |
68 | public static String getString(String str) {
69 | try {
70 | if (null == instance) {
71 | getInstance();
72 | }
73 | return PROPERTIES.getProperty(str);
74 | } catch (Exception e) {
75 | e.printStackTrace();
76 | return "";
77 | }
78 | }
79 |
80 | public static boolean getBoolean(String str) {
81 | try {
82 | if (null == instance) {
83 | getInstance();
84 | }
85 | return Boolean.parseBoolean(PROPERTIES.getProperty(str));
86 | } catch (Exception e) {
87 | e.printStackTrace();
88 | return false;
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/ErrorCode.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net;
2 |
3 | import java.util.HashMap;
4 |
5 | /**
6 | * @author zhoumengkang
7 | * @date 17/7/26.
8 | */
9 | public class ErrorCode {
10 |
11 | public static final int SYSTEM_ERROR = 1000;
12 | public static final int METHOD_CAN_NOT_BE_NULL = 1001;
13 | public static final int PARAMETER_NOT_FOUND = 1002;
14 | public static final int PARAMETER_FORMAT_ERROR = 1003;
15 |
16 | public static final HashMap ERROR_MESSAGES = new HashMap<>();
17 |
18 | static {
19 | ERROR_MESSAGES.put(METHOD_CAN_NOT_BE_NULL,"method 不能为空");
20 | ERROR_MESSAGES.put(SYSTEM_ERROR,"系统异常");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/Request.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net;
2 |
3 | import java.util.HashMap;
4 | import java.util.List;
5 | import java.util.Map;
6 |
7 | import io.netty.handler.codec.http.HttpMethod;
8 |
9 | /**
10 | * @author zhoumengkang
11 | * @date 17/7/26.
12 | */
13 | public class Request {
14 | private String ip;
15 | private HttpMethod method;
16 | private Map> parameters = new HashMap>(); // get 和 post 的键值对都存储在这里
17 | private String postBody = null; // post 请求时的非键值对内容
18 |
19 | public String getIp() {
20 | return ip;
21 | }
22 |
23 | public void setIp(String ip) {
24 | this.ip = ip;
25 | }
26 |
27 | public HttpMethod getMethod() {
28 | return method;
29 | }
30 |
31 | public void setMethod(HttpMethod method) {
32 | this.method = method;
33 | }
34 |
35 | public Map> getParameters() {
36 | return parameters;
37 | }
38 |
39 | public void setParameters(Map> parameters) {
40 | this.parameters = parameters;
41 | }
42 |
43 | public String getPostBody() {
44 | return postBody;
45 | }
46 |
47 | public void setPostBody(String postBody) {
48 | this.postBody = postBody;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/RequestHandler.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net;
2 |
3 | import java.lang.reflect.Constructor;
4 | import java.lang.reflect.InvocationTargetException;
5 | import java.lang.reflect.Method;
6 | import java.net.InetSocketAddress;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import com.alibaba.fastjson.JSON;
11 |
12 | import io.netty.channel.ChannelHandlerContext;
13 | import io.netty.handler.codec.http.HttpMethod;
14 | import io.netty.handler.codec.http.HttpRequest;
15 | import io.netty.handler.codec.http.QueryStringDecoder;
16 | import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
17 | import io.netty.handler.codec.http.multipart.InterfaceHttpData;
18 | import io.netty.handler.codec.http.multipart.MixedAttribute;
19 | import io.netty.util.CharsetUtil;
20 |
21 | /**
22 | * @author zhoumengkang
23 | * @date 17/7/25.
24 | */
25 | public class RequestHandler {
26 |
27 | /**
28 | * 我们约定的请求的 method 参数 来查找控制
29 | */
30 | private static final String REQUEST_METHOD = "method";
31 |
32 | private static Request requestFetch(ChannelHandlerContext ctx, Object msg){
33 |
34 | Request request = new Request();
35 |
36 | HttpRequest req = (HttpRequest)msg;
37 | String uri = req.uri();
38 |
39 | // ip
40 | String clientIP = (String) req.headers().get("X-Forwarded-For");
41 | if (clientIP == null) {
42 | InetSocketAddress remoteSocket = (InetSocketAddress) ctx.channel().remoteAddress();
43 | clientIP = remoteSocket.getAddress().getHostAddress();
44 | }
45 | request.setIp(clientIP);
46 |
47 | // method
48 | request.setMethod(req.method());
49 |
50 | // get
51 | QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri);
52 | if (queryStringDecoder.parameters().size() > 0) {
53 | request.getParameters().putAll(queryStringDecoder.parameters());
54 | }
55 |
56 | // post
57 | if (req.method().equals(HttpMethod.POST)) {
58 | HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req);
59 | try {
60 | List postList = decoder.getBodyHttpDatas();
61 | for (InterfaceHttpData data : postList) {
62 | List values = new ArrayList<>();
63 | MixedAttribute value = (MixedAttribute) data;
64 | value.setCharset(CharsetUtil.UTF_8);
65 | values.add(value.getValue());
66 | request.getParameters().put(data.getName(), values);
67 | }
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | }
71 | }
72 |
73 | return request;
74 | }
75 |
76 | public static byte[] response(ChannelHandlerContext ctx, Object msg) {
77 |
78 | Request request = requestFetch(ctx,msg);
79 |
80 | if (!request.getParameters().containsKey(REQUEST_METHOD)) {
81 | return responseError(ErrorCode.METHOD_CAN_NOT_BE_NULL);
82 | }
83 |
84 | String method = request.getParameters().get(REQUEST_METHOD).get(0);
85 | String[] classAndMethodArray = method.split("\\.");
86 |
87 | if (classAndMethodArray.length < 2) {
88 | return responseError(ErrorCode.METHOD_CAN_NOT_BE_NULL);
89 | }
90 |
91 | String clazz = getApiController(classAndMethodArray[0]);
92 | String function = classAndMethodArray[1];
93 |
94 | Object obj = invoke(clazz, function,request);
95 |
96 | return encode(new Response(obj));
97 | }
98 |
99 | private static byte[] encode(Object object) {
100 | String data = JSON.toJSONString(object);
101 | return data.getBytes();
102 | }
103 |
104 | /**
105 | * 返回错误信息
106 | *
107 | * @return
108 | */
109 | private static byte[] responseError(int errorCode) {
110 | Response response = new Response(errorCode);
111 | return encode(response);
112 | }
113 |
114 | private static String getApiController(String method) {
115 | char[] tmp = method.toCharArray();
116 | tmp[0] -= 32;
117 | return String.valueOf(tmp);
118 | }
119 |
120 | private static Object invoke(String clazz, String function,Request request) {
121 | Class> classname;
122 | Object classObject;
123 | Constructor constructor;
124 | Method methodName;
125 | Object result = null;
126 |
127 | try {
128 | classname = Class.forName("api.mengkang.net.api." + clazz + "Controller");
129 | constructor = classname.getConstructor(Request.class);
130 | classObject = constructor.newInstance(request);
131 | methodName = classname.getMethod(function);
132 | result = methodName.invoke(classObject);
133 | } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
134 | e.printStackTrace();
135 | return responseError(ErrorCode.SYSTEM_ERROR);
136 | }
137 |
138 | return result;
139 | }
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/Response.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net;
2 |
3 | /**
4 | * @author zhoumengkang
5 | * @date 17/7/26.
6 | */
7 | public class Response {
8 | /**
9 | * 成功时 0 ,如果大于 0 则表示则显示error_msg
10 | */
11 | private int errorCode;
12 | private String errorMsg;
13 | private Object data;
14 |
15 | public int getErrorCode() {
16 | return errorCode;
17 | }
18 |
19 | public void setErrorCode(int errorCode) {
20 | this.errorCode = errorCode;
21 | }
22 |
23 | public String getErrorMsg() {
24 | return errorMsg;
25 | }
26 |
27 | public void setErrorMsg(String errorMsg) {
28 | this.errorMsg = errorMsg;
29 | }
30 |
31 | public Object getData() {
32 | return data;
33 | }
34 |
35 | public void setData(Object data) {
36 | this.data = data;
37 | }
38 |
39 | public Response(int errorCode) {
40 | this.errorCode = errorCode;
41 | if (ErrorCode.ERROR_MESSAGES.containsKey(errorCode)){
42 | this.errorMsg = ErrorCode.ERROR_MESSAGES.get(errorCode);
43 | }
44 | }
45 |
46 | public Response(int errorCode, String errorMsg) {
47 | this.errorCode = errorCode;
48 | this.errorMsg = errorMsg;
49 | }
50 |
51 | public Response(Object data) {
52 | this.data = data;
53 | }
54 |
55 | public Response() {
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/api/BaseController.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.api;
2 |
3 | import api.mengkang.net.ErrorCode;
4 | import api.mengkang.net.Request;
5 | import api.mengkang.net.Response;
6 |
7 | /**
8 | * @author zhoumengkang
9 | * @date 17/7/26.
10 | */
11 | public class BaseController {
12 | Request request;
13 |
14 | public BaseController(Request request) {
15 | this.request = request;
16 | }
17 |
18 | protected Response responseError(int errorCode) {
19 | return new Response(errorCode);
20 | }
21 |
22 | protected Response parameterNotFound(String parameterName){
23 | return new Response(ErrorCode.PARAMETER_NOT_FOUND,"参数: " + parameterName + " 不可缺省");
24 | }
25 |
26 | protected Response parameterFormatError(String parameterName){
27 | return new Response(ErrorCode.PARAMETER_FORMAT_ERROR,"参数: " + parameterName + " 格式错误");
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/api/UserController.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.api;
2 |
3 | import api.mengkang.net.Request;
4 | import api.mengkang.net.entity.User;
5 | import api.mengkang.net.model.UserModel;
6 |
7 | /**
8 | * @author zhoumengkang
9 | * @date 17/7/25.
10 | */
11 | public class UserController extends BaseController {
12 |
13 | public UserController(Request request) {
14 | super(request);
15 | }
16 |
17 | public Object get(){
18 |
19 | int uid;
20 |
21 | if (!request.getParameters().containsKey("id")){
22 | return parameterNotFound("uid");
23 | }
24 |
25 | try{
26 | uid = Integer.parseInt(request.getParameters().get("id").get(0));
27 | }catch (NumberFormatException e){
28 | return parameterFormatError("uid");
29 | }
30 |
31 | User user = UserModel.getUserInfoById(uid);
32 |
33 | if (user == null) {
34 | return parameterFormatError("uid");
35 | }
36 |
37 | return user;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/dao/UserDao.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.dao;
2 |
3 | import api.mengkang.net.entity.User;
4 | import api.mengkang.net.utils.mysql.MySelect;
5 | import api.mengkang.net.utils.mysql.Mysql;
6 |
7 | /**
8 | * @author zhoumengkang
9 | * @date 17/7/26.
10 | */
11 | public class UserDao {
12 | public static User getById(int id){
13 | String sql = "select id,age,sex,username from `user` where id=?";
14 | MySelect mySelect = new MySelect<>(new User());
15 | return mySelect.get(sql,id);
16 | }
17 |
18 | public static int add(User user){
19 | return Mysql.insert("insert into user (age,sex,username) values (?,?,?)",
20 | user.getAge(),user.getSex(),user.getUsername()
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/entity/User.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.entity;
2 |
3 | /**
4 | * @author zhoumengkang
5 | * @date 17/7/26.
6 | */
7 | public class User {
8 | private Integer id;
9 | private Integer age;
10 | private Integer sex;
11 | private String username;
12 |
13 | public User() {
14 | }
15 |
16 | public User(Integer id, Integer age, Integer sex, String username) {
17 | this.id = id;
18 | this.age = age;
19 | this.sex = sex;
20 | this.username = username;
21 | }
22 |
23 | public Integer getId() {
24 | return id;
25 | }
26 |
27 | public void setId(Integer id) {
28 | this.id = id;
29 | }
30 |
31 | public Integer getAge() {
32 | return age;
33 | }
34 |
35 | public void setAge(Integer age) {
36 | this.age = age;
37 | }
38 |
39 | public Integer getSex() {
40 | return sex;
41 | }
42 |
43 | public void setSex(Integer sex) {
44 | this.sex = sex;
45 | }
46 |
47 | public String getUsername() {
48 | return username;
49 | }
50 |
51 | public void setUsername(String username) {
52 | this.username = username;
53 | }
54 |
55 | @Override
56 | public String toString() {
57 | return "User{" +
58 | "id=" + id +
59 | ", age=" + age +
60 | ", sex=" + sex +
61 | ", username='" + username + '\'' +
62 | '}';
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/model/UserModel.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.model;
2 |
3 | import api.mengkang.net.dao.UserDao;
4 | import api.mengkang.net.entity.User;
5 |
6 | /**
7 | * @author zhoumengkang
8 | * @date 17/7/26.
9 | */
10 | public class UserModel {
11 | public static User getUserInfoById(int uid){
12 | return UserDao.getById(uid);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/netty/HttpServer.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.netty;
2 |
3 | import api.mengkang.net.Config;
4 | import io.netty.bootstrap.ServerBootstrap;
5 | import io.netty.channel.Channel;
6 | import io.netty.channel.EventLoopGroup;
7 | import io.netty.channel.nio.NioEventLoopGroup;
8 | import io.netty.channel.socket.nio.NioServerSocketChannel;
9 | import io.netty.handler.logging.LogLevel;
10 | import io.netty.handler.logging.LoggingHandler;
11 | import io.netty.handler.ssl.SslContext;
12 |
13 | /**
14 | * @author zhoumengkang
15 | */
16 | public final class HttpServer {
17 |
18 | private static final int PORT = Config.getInt("server.port");
19 |
20 | public static void main(String[] args) throws Exception {
21 | final SslContext sslCtx = null;
22 |
23 | EventLoopGroup bossGroup = new NioEventLoopGroup(1);
24 | EventLoopGroup workerGroup = new NioEventLoopGroup();
25 | try {
26 | ServerBootstrap b = new ServerBootstrap();
27 | b.group(bossGroup, workerGroup)
28 | .channel(NioServerSocketChannel.class)
29 | .handler(new LoggingHandler(LogLevel.INFO))
30 | .childHandler(new HttpServerInitializer(sslCtx));
31 |
32 | Channel ch = b.bind(PORT).sync().channel();
33 | ch.closeFuture().sync();
34 | } finally {
35 | bossGroup.shutdownGracefully();
36 | workerGroup.shutdownGracefully();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/netty/HttpServerHandler.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.netty;
2 |
3 | import api.mengkang.net.RequestHandler;
4 | import io.netty.buffer.Unpooled;
5 | import io.netty.channel.ChannelFutureListener;
6 | import io.netty.channel.ChannelHandlerAdapter;
7 | import io.netty.channel.ChannelHandlerContext;
8 | import io.netty.handler.codec.AsciiString;
9 | import io.netty.handler.codec.http.DefaultFullHttpResponse;
10 | import io.netty.handler.codec.http.FullHttpResponse;
11 | import io.netty.handler.codec.http.HttpHeaderUtil;
12 | import io.netty.handler.codec.http.HttpHeaderValues;
13 | import io.netty.handler.codec.http.HttpRequest;
14 |
15 | import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
16 | import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
17 | import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
18 | import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
19 | import static io.netty.handler.codec.http.HttpResponseStatus.OK;
20 | import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
21 |
22 |
23 | /**
24 | * @author zhoumengkang
25 | */
26 | public class HttpServerHandler extends ChannelHandlerAdapter {
27 |
28 | @Override
29 | public void channelReadComplete(ChannelHandlerContext ctx) {
30 | ctx.flush();
31 | }
32 |
33 | @Override
34 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
35 | if (msg instanceof HttpRequest) {
36 | HttpRequest req = (HttpRequest) msg;
37 |
38 | if (HttpHeaderUtil.is100ContinueExpected(req)) {
39 | ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
40 | }
41 | boolean keepAlive = HttpHeaderUtil.isKeepAlive(req);
42 | FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(
43 | RequestHandler.response(ctx,msg)));
44 | // 返回 json 格式的数据
45 | response.headers().set(CONTENT_TYPE,new AsciiString("application/json; charset=utf-8"));
46 | response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
47 |
48 | if (!keepAlive) {
49 | ctx.write(response).addListener(ChannelFutureListener.CLOSE);
50 | } else {
51 | response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
52 | ctx.write(response);
53 | }
54 | }
55 | }
56 |
57 | @Override
58 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
59 | cause.printStackTrace();
60 | ctx.close();
61 | }
62 | }
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/netty/HttpServerInitializer.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.netty;
2 |
3 | import io.netty.channel.ChannelInitializer;
4 | import io.netty.channel.ChannelPipeline;
5 | import io.netty.channel.socket.SocketChannel;
6 | import io.netty.handler.codec.http.HttpContentCompressor;
7 | import io.netty.handler.codec.http.HttpObjectAggregator;
8 | import io.netty.handler.codec.http.HttpServerCodec;
9 | import io.netty.handler.ssl.SslContext;
10 |
11 |
12 | /**
13 | * @author zhoumengkang
14 | */
15 | public class HttpServerInitializer extends ChannelInitializer {
16 |
17 | private final SslContext sslCtx;
18 |
19 | public HttpServerInitializer(SslContext sslCtx) {
20 | this.sslCtx = sslCtx;
21 | }
22 |
23 | @Override
24 | public void initChannel(SocketChannel ch) throws Exception {
25 | ChannelPipeline pipeline = ch.pipeline();
26 | if (sslCtx != null) {
27 | pipeline.addLast(sslCtx.newHandler(ch.alloc()));
28 | }
29 | pipeline.addLast(new HttpServerCodec());
30 | pipeline.addLast(new HttpObjectAggregator(65536));
31 | // 增加 gzip 压缩
32 | pipeline.addLast(new HttpContentCompressor(1));
33 | pipeline.addLast(new HttpServerHandler());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/utils/mysql/DMLTypes.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.utils.mysql;
2 |
3 |
4 | public enum DMLTypes {
5 | INSERT,
6 | SELECT,
7 | UPDATE,
8 | DELETE,
9 | REPLACE,
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/utils/mysql/DbFiled.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.utils.mysql;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | @Documented
10 | @Retention(RetentionPolicy.RUNTIME)
11 | @Target({ElementType.FIELD})
12 | public @interface DbFiled {
13 | String value();
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/utils/mysql/JdbcPool.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.utils.mysql;
2 |
3 | import java.io.InputStreamReader;
4 | import java.sql.Connection;
5 | import java.sql.ResultSet;
6 | import java.sql.SQLException;
7 | import java.sql.Statement;
8 | import java.util.Properties;
9 |
10 | import javax.sql.DataSource;
11 |
12 | import org.apache.commons.dbcp.BasicDataSourceFactory;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 |
16 | public class JdbcPool {
17 |
18 | private static final Logger logger = LoggerFactory.getLogger(JdbcPool.class);
19 |
20 | /**
21 | * 在 java 中,编写数据库连接池需实现 java.sql.DataSource 接口
22 | * DBCP 连接池就是 java.sql.DataSource 接口的一个具体实现
23 | */
24 | private static DataSource writeDataSource = null;
25 | private static DataSource readDataSource = null;
26 |
27 | static {
28 | try {
29 | Properties writeProp = new Properties();
30 | writeProp.load(new InputStreamReader(JdbcPool.class.getResourceAsStream("/write.db.properties"), "UTF-8"));
31 | writeDataSource = BasicDataSourceFactory.createDataSource(writeProp);
32 |
33 | Properties readProp = new Properties();
34 | readProp.load(new InputStreamReader(JdbcPool.class.getResourceAsStream("/read.db.properties"), "UTF-8"));
35 | readDataSource = BasicDataSourceFactory.createDataSource(readProp);
36 |
37 | } catch (Exception e) {
38 | logger.error("load db properties error",e);
39 | throw new ExceptionInInitializerError(e);
40 | }
41 | }
42 |
43 | public static Connection getWriteConnection() throws SQLException {
44 | return writeDataSource.getConnection();
45 | }
46 |
47 | public static Connection getReadConnection() throws SQLException {
48 | return readDataSource.getConnection();
49 | }
50 |
51 | public static void release(Connection conn, Statement st, ResultSet rs) {
52 | if (rs != null) {
53 | try {
54 | rs.close();
55 | } catch (Exception e) {
56 | e.printStackTrace();
57 | }
58 | rs = null;
59 | }
60 |
61 | if (st != null) {
62 | try {
63 | st.close();
64 | } catch (Exception e) {
65 | e.printStackTrace();
66 | }
67 | }
68 |
69 | if (conn != null) {
70 | try {
71 | conn.close();
72 | } catch (Exception e) {
73 | e.printStackTrace();
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/utils/mysql/MySelect.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.utils.mysql;
2 |
3 | import java.lang.reflect.Field;
4 | import java.sql.Connection;
5 | import java.sql.Date;
6 | import java.sql.PreparedStatement;
7 | import java.sql.ResultSet;
8 | import java.sql.SQLException;
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | public class MySelect extends Mysql {
18 |
19 | private final Logger logger = LoggerFactory.getLogger(this.getClass());
20 |
21 | private Class clazz;
22 |
23 | private Map fieldMap = new HashMap<>();
24 |
25 | public MySelect(A bean) {
26 | this.clazz = bean.getClass();
27 | fieldMapInit();
28 | }
29 |
30 | private void fieldMapInit() {
31 | Field[] fields = clazz.getDeclaredFields();
32 |
33 | for (Field field : fields) {
34 | if (field.isAnnotationPresent(DbFiled.class)) {
35 | fieldMap.put(field.getAnnotation(DbFiled.class).value(), field);
36 | } else {
37 | fieldMap.put(field.getName(), field);
38 | }
39 | }
40 | }
41 |
42 | // todo select * xxx
43 | private String[] parseSelectFields(String sql) {
44 | sql = sql.toLowerCase();
45 |
46 | String[] fieldArray = sql.substring(sql.indexOf("select") + 6, sql.indexOf("from")).split(",");
47 | int length = fieldArray.length;
48 | String[] fields = new String[length];
49 |
50 | for (int i = 0; i < length; i++) {
51 | fields[i] = fieldArray[i].trim().replace("`", "");
52 | }
53 |
54 | return fields;
55 | }
56 |
57 | @SuppressWarnings("unchecked")
58 | public A resultSet(String[] selectFields,ResultSet resultSet){
59 |
60 | A bean = null;
61 |
62 | try{
63 | bean = (A) Class.forName(clazz.getName()).newInstance();
64 |
65 | for (int i = 0; i < selectFields.length; i++) {
66 | int j = i + 1;
67 | Field field = fieldMap.get(selectFields[i]);
68 | field.setAccessible(true);
69 | Class fieldClass = field.getType();
70 | if (fieldClass == String.class) {
71 | field.set(bean, resultSet.getString(j));
72 | } else if (fieldClass == int.class || fieldClass == Integer.class) {
73 | field.set(bean, resultSet.getInt(j));
74 | } else if (fieldClass == float.class || fieldClass == Float.class) {
75 | field.set(bean, resultSet.getFloat(j));
76 | } else if (fieldClass == double.class || fieldClass == Double.class) {
77 | field.set(bean, resultSet.getDouble(j));
78 | } else if (fieldClass == long.class || fieldClass == Long.class) {
79 | field.set(bean, resultSet.getLong(j));
80 | } else if (fieldClass == Date.class) {
81 | field.set(bean, resultSet.getDate(j));
82 | }
83 | }
84 | }catch (SQLException e){
85 | logger.error("resultSet parse error", e);
86 | } catch (IllegalAccessException | ClassNotFoundException | InstantiationException e) {
87 | e.printStackTrace();
88 | }
89 |
90 | return bean;
91 | }
92 |
93 | public A get(String sql, Object... params) {
94 |
95 | grammarCheck(sql, DMLTypes.SELECT);
96 | int paramSize = getParameterNum(sql, params);
97 |
98 | Connection conn = null;
99 | PreparedStatement statement = null;
100 | ResultSet resultSet = null;
101 |
102 | try {
103 | conn = JdbcPool.getReadConnection();
104 | statement = conn.prepareStatement(sql);
105 |
106 | if (paramSize > 0) {
107 | statement = bindParameters(statement, params);
108 | }
109 |
110 | resultSet = statement.executeQuery();
111 | if (resultSet.next()){
112 | String[] selectFields = parseSelectFields(sql);
113 | return resultSet(selectFields,resultSet);
114 | }
115 | } catch (SQLException e) {
116 | logger.error("sql error", e);
117 | } finally {
118 | JdbcPool.release(conn, statement, resultSet);
119 | }
120 | return null;
121 | }
122 |
123 | public List list(String sql, Object... params) {
124 | List beanList = new ArrayList<>();
125 |
126 | grammarCheck(sql, DMLTypes.SELECT);
127 | int paramSize = getParameterNum(sql, params);
128 |
129 | Connection conn = null;
130 | PreparedStatement statement = null;
131 | ResultSet resultSet = null;
132 | try {
133 | conn = JdbcPool.getReadConnection();
134 | statement = conn.prepareStatement(sql);
135 |
136 | if (paramSize > 0) {
137 | statement = bindParameters(statement, params);
138 | }
139 |
140 | resultSet = statement.executeQuery();
141 | String[] selectFields = parseSelectFields(sql);
142 | while (resultSet.next()) {
143 | beanList.add(resultSet(selectFields,resultSet));
144 | }
145 | } catch (Exception e) {
146 | logger.error("sql error", e);
147 | } finally {
148 | JdbcPool.release(conn, statement, resultSet);
149 | }
150 |
151 | return beanList;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/main/java/api/mengkang/net/utils/mysql/Mysql.java:
--------------------------------------------------------------------------------
1 | package api.mengkang.net.utils.mysql;
2 |
3 | import java.sql.Connection;
4 | import java.sql.Date;
5 | import java.sql.PreparedStatement;
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.sql.Statement;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | /**
14 | * @author zhoumengkang
15 | */
16 |
17 | public class Mysql {
18 |
19 | private static final Logger logger = LoggerFactory.getLogger(Mysql.class);
20 |
21 | static void grammarCheck(String sql,DMLTypes sqlType){
22 |
23 | String dmlType = sqlType.toString().toLowerCase();
24 |
25 | try {
26 | if (!sql.toLowerCase().startsWith(dmlType)) {
27 | throw new Exception(dmlType + " statement needed");
28 | }
29 |
30 | if(!dmlType.equals(DMLTypes.INSERT.toString().toLowerCase()) && sql.toLowerCase().indexOf("where") < 1){
31 | throw new Exception("where statement needed");
32 | }
33 | } catch (Exception e) {
34 | logger.error(e.getMessage());
35 | }
36 | }
37 |
38 | static int getParameterNum(String sql, Object... params) {
39 | int paramSize = sql.length() - sql.replaceAll("\\?", "").length();
40 |
41 | try {
42 | if (paramSize != params.length) {
43 | throw new Exception("parameter's num error");
44 | }
45 | } catch (Exception e) {
46 | logger.error(e.getMessage());
47 | }
48 |
49 | return paramSize;
50 | }
51 |
52 | /**
53 | * bind parameters
54 | *
55 | * @param statement
56 | * @param params
57 | * @return
58 | * @throws SQLException
59 | */
60 | static PreparedStatement bindParameters(PreparedStatement statement, Object... params) throws SQLException {
61 |
62 | int paramSize = params.length;
63 |
64 | for (int i = 1; i <= paramSize; i++) {
65 | Object param = params[i - 1];
66 | if (param instanceof Integer) {
67 | statement.setInt(i, (Integer) param);
68 | } else if (param instanceof String) {
69 | statement.setString(i, (String) param);
70 | } else if (param instanceof Float) {
71 | statement.setFloat(i, (Float) param);
72 | } else if (param instanceof Long) {
73 | statement.setLong(i, (Long) param);
74 | } else if (param instanceof Double) {
75 | statement.setDouble(i, (Double) param);
76 | } else if (param instanceof Date) {
77 | statement.setDate(i, (Date) param);
78 | } else {
79 | statement.setObject(i, param);
80 | }
81 | }
82 |
83 | return statement;
84 | }
85 |
86 | /**
87 | * 插入操作
88 | *
89 | * @param sql
90 | * @param params
91 | * @return
92 | */
93 | public static int insert(String sql, Object... params) {
94 |
95 | grammarCheck(sql,DMLTypes.INSERT);
96 | int paramSize = getParameterNum(sql,params);
97 |
98 | Connection conn = null;
99 | PreparedStatement statement = null;
100 | ResultSet rs = null;
101 | int id = 0;
102 |
103 | try {
104 | conn = JdbcPool.getWriteConnection();
105 | statement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
106 |
107 | if (paramSize > 0) {
108 | statement = bindParameters(statement, params);
109 | }
110 |
111 | statement.executeUpdate();
112 | rs = statement.getGeneratedKeys();
113 | if (rs.next()) {
114 | id = rs.getInt(1);
115 | }
116 | } catch (SQLException e) {
117 | logger.error("sql error",e);
118 | } finally {
119 | JdbcPool.release(conn, statement, rs);
120 | }
121 |
122 | return id;
123 | }
124 |
125 | /**
126 | * 删除操作
127 | *
128 | * @param sql
129 | * @param params
130 | * @return
131 | */
132 | public static int delete(String sql, Object... params) {
133 | return update(sql, params);
134 | }
135 |
136 | /**
137 | * 更新操作
138 | *
139 | * @param sql
140 | * @param params
141 | * @return
142 | */
143 | public static int update(String sql, Object... params) {
144 |
145 | if (!sql.toLowerCase().startsWith(DMLTypes.DELETE.toString().toLowerCase())
146 | && !sql.toLowerCase().startsWith(DMLTypes.UPDATE.toString().toLowerCase())
147 | && !sql.toLowerCase().startsWith(DMLTypes.REPLACE.toString().toLowerCase())) {
148 | try {
149 | throw new Exception("update statement needed");
150 | } catch (Exception e) {
151 | e.printStackTrace();
152 | }
153 | }
154 |
155 | int paramSize = getParameterNum(sql,params);
156 |
157 | Connection conn = null;
158 | PreparedStatement statement = null;
159 | int row = 0;
160 |
161 | try {
162 | conn = JdbcPool.getWriteConnection();
163 | statement = conn.prepareStatement(sql);
164 |
165 | if (paramSize > 0) {
166 | statement = bindParameters(statement, params);
167 | }
168 |
169 | row = statement.executeUpdate();
170 | } catch (SQLException e) {
171 | logger.error("sql error",e);
172 | } finally {
173 | JdbcPool.release(conn, statement, null);
174 | }
175 |
176 | return row;
177 | }
178 |
179 | public static String getValue(String sql, Object... params) {
180 | grammarCheck(sql,DMLTypes.SELECT);
181 | int paramSize = getParameterNum(sql,params);
182 |
183 | Connection conn = null;
184 | PreparedStatement statement = null;
185 | ResultSet rs = null;
186 | String res = null;
187 |
188 | try {
189 | conn = JdbcPool.getReadConnection();
190 | statement = conn.prepareStatement(sql);
191 |
192 | if (paramSize > 0) {
193 | statement = bindParameters(statement, params);
194 | }
195 |
196 | rs = statement.executeQuery();
197 | if (rs.next()) {
198 | res = rs.getString(1);
199 | }
200 | } catch (SQLException e) {
201 | logger.error("sql error", e);
202 | } finally {
203 | JdbcPool.release(conn, statement, rs);
204 | }
205 |
206 | return res;
207 | }
208 |
209 | public static int getIntValue(String sql, Object... params) {
210 |
211 | grammarCheck(sql,DMLTypes.SELECT);
212 | int paramSize = getParameterNum(sql,params);
213 |
214 | Connection conn = null;
215 | PreparedStatement statement = null;
216 | ResultSet rs = null;
217 | int res = 0;
218 |
219 | try {
220 | conn = JdbcPool.getReadConnection();
221 | statement = conn.prepareStatement(sql);
222 |
223 | if (paramSize > 0) {
224 | statement = bindParameters(statement, params);
225 | }
226 |
227 | rs = statement.executeQuery();
228 | if (rs.next()) {
229 | res = rs.getInt(1);
230 | }
231 | } catch (SQLException e) {
232 | logger.error("sql error",e);
233 | } finally {
234 | JdbcPool.release(conn, statement, rs);
235 | }
236 |
237 | return res;
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/src/main/resources/api.properties:
--------------------------------------------------------------------------------
1 | server.port=9009
--------------------------------------------------------------------------------
/src/main/resources/read.db.properties:
--------------------------------------------------------------------------------
1 | #连接设置
2 | driverClassName=com.mysql.jdbc.Driver
3 | url=jdbc:mysql://127.0.0.1:3306/segmentfault
4 | username=root
5 | password=zmkzmk
6 |
7 | #初始化连接
8 | initialSize=2
9 |
10 | #最大连接数量
11 | maxActive=10
12 |
13 | #最大空闲连接
14 | maxIdle=5
15 |
16 | #最小空闲连接
17 | minIdle=2
18 |
19 | #超时等待时间以毫秒为单位
20 | maxWait=10000
21 |
22 |
23 | #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
24 | #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
25 | connectionProperties=useUnicode=true;characterEncoding=utf8
26 |
27 | #指定由连接池所创建的连接的自动提交(auto-commit)状态。
28 | defaultAutoCommit=true
29 |
30 | #driver default 指定由连接池所创建的连接的只读(read-only)状态。
31 | #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
32 | defaultReadOnly=true
33 |
34 | #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
35 | #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
36 | defaultTransactionIsolation=READ_UNCOMMITTED
--------------------------------------------------------------------------------
/src/main/resources/write.db.properties:
--------------------------------------------------------------------------------
1 | #连接设置
2 | driverClassName=com.mysql.jdbc.Driver
3 | url=jdbc:mysql://127.0.0.1:3306/segmentfault
4 | username=root
5 | password=zmkzmk
6 |
7 | #初始化连接
8 | initialSize=2
9 |
10 | #最大连接数量
11 | maxActive=10
12 |
13 | #最大空闲连接
14 | maxIdle=5
15 |
16 | #最小空闲连接
17 | minIdle=2
18 |
19 | #超时等待时间以毫秒为单位
20 | maxWait=10000
21 |
22 |
23 | #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
24 | #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
25 | #connectionProperties=useUnicode=true;characterEncoding=utf8mb4
26 | connectionProperties=useUnicode=true;characterEncoding=utf8
27 |
28 | #指定由连接池所创建的连接的自动提交(auto-commit)状态。
29 | defaultAutoCommit=true
30 |
31 | #driver default 指定由连接池所创建的连接的只读(read-only)状态。
32 | #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
33 | defaultReadOnly=false
34 |
35 | #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
36 | #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
37 | defaultTransactionIsolation=READ_UNCOMMITTED
--------------------------------------------------------------------------------
/src/test/java/TestUserInfo.java:
--------------------------------------------------------------------------------
1 | import api.mengkang.net.Request;
2 | import api.mengkang.net.api.UserController;
3 | import org.junit.Test;
4 |
5 | /**
6 | * @author zhoumengkang
7 | * @date 17/7/25.
8 | */
9 | public class TestUserInfo {
10 |
11 | @Test
12 | public void getUserInfo(){
13 | Request request = null;
14 | UserController userController = new UserController(request);
15 | Object res = userController.get();
16 | System.out.println(res);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------