diff --git a/docs/Authorize.html b/docs/Authorize.html new file mode 100644 index 0000000..a884827 --- /dev/null +++ b/docs/Authorize.html @@ -0,0 +1,58 @@ +Authorize
+
+
+ +
+ +

Authorize

+ +
+
+ +

URL

+ +

http://sola.love/ww/api/authorize

+ +
+ +

Method

+ +

POST

+ +
+ +

Parameters

+ + + +
+ +

Response Code

+ + + +
+ +

Signature

+ +

Created by Sola on 2/15/2015

\ No newline at end of file diff --git a/docs/绑定微信请求.html b/docs/绑定微信请求.html new file mode 100644 index 0000000..486a1ae --- /dev/null +++ b/docs/绑定微信请求.html @@ -0,0 +1,82 @@ +绑定微信请求
+
+
+ +
+ +

绑定微信请求

+ +
+ +

URL

+ +

http://sola.love

+ +

Method

+ +

POST

+ +
+ +

Params

+ +
+ +

More

+ +

片区代码

+ +
+ +

Author

+ +

LiuYue(hangxingliu)

+ +

Date

+ +

2015/11/28

\ No newline at end of file diff --git a/src/main/java/love/sola/netsupport/api/Authorize.java b/src/main/java/love/sola/netsupport/api/Authorize.java new file mode 100644 index 0000000..2ca3736 --- /dev/null +++ b/src/main/java/love/sola/netsupport/api/Authorize.java @@ -0,0 +1,77 @@ +package love.sola.netsupport.api; + +import com.google.gson.Gson; +import love.sola.netsupport.config.Settings; +import love.sola.netsupport.sql.SQLCore; +import love.sola.netsupport.wechat.Command; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static love.sola.netsupport.config.Lang.lang; + +/** + * *********************************************** + * Created by Sola on 2015/12/2. + * Don't modify this source without my agreement + * *********************************************** + */ +@WebServlet(name = "Authorize", urlPatterns = "/api/authorize", loadOnStartup = 21) +public class Authorize extends HttpServlet { + + private Gson gson = SQLCore.gson; + + public static Map fetchedTime = new ConcurrentHashMap<>(); + public static Map fetchedCommand = new ConcurrentHashMap<>(); + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.setCharacterEncoding("utf-8"); + response.setCharacterEncoding("utf-8"); + response.addHeader("Content-type", "text/json;charset=utf-8"); + PrintWriter out = response.getWriter(); + String wechat = request.getParameter("wechat"); + out.println(gson.toJson(authorize(wechat))); + out.close(); + } + + private Response authorize(String wechat) { + if (wechat == null) { + return new Response(Response.ResponseCode.PARAMETER_REQUIRED); + } + Long l = fetchedTime.remove(wechat); + Command c = fetchedCommand.remove(wechat); + if (l == null || c == null) { + return new Response(Response.ResponseCode.AUTHORIZE_FAILED); + } + if (l < System.currentTimeMillis() - Settings.I.User_Command_Timeout) { + return new Response(Response.ResponseCode.AUTHORIZE_FAILED); + } + switch (c) { + case REGISTER: + Register.authorized.put(wechat, System.currentTimeMillis()); + break; + default: + return new Response(Response.ResponseCode.AUTHORIZE_FAILED); + } + return new Response(Response.ResponseCode.OK); + } + + + @SuppressWarnings("Duplicates") + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.setCharacterEncoding("utf-8"); + response.setCharacterEncoding("utf-8"); + response.addHeader("Content-type", "text/plain;charset=utf-8"); + PrintWriter out = response.getWriter(); + out.println(lang("Illegal_Request")); + out.close(); + } + +} diff --git a/src/main/java/love/sola/netsupport/api/GetUser.java b/src/main/java/love/sola/netsupport/api/GetUser.java index 9670290..36458a4 100644 --- a/src/main/java/love/sola/netsupport/api/GetUser.java +++ b/src/main/java/love/sola/netsupport/api/GetUser.java @@ -2,6 +2,7 @@ package love.sola.netsupport.api; import com.google.gson.Gson; import love.sola.netsupport.pojo.User; +import love.sola.netsupport.sql.SQLCore; import love.sola.netsupport.sql.TableUser; import javax.servlet.ServletConfig; @@ -22,12 +23,11 @@ import java.io.PrintWriter; @WebServlet(name = "GetUser",urlPatterns = "/api/getuser",loadOnStartup = 1) public class GetUser extends HttpServlet { - private Gson gson = null; + private Gson gson = SQLCore.gson; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - gson = new Gson(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { diff --git a/src/main/java/love/sola/netsupport/api/Register.java b/src/main/java/love/sola/netsupport/api/Register.java new file mode 100644 index 0000000..9a16ad1 --- /dev/null +++ b/src/main/java/love/sola/netsupport/api/Register.java @@ -0,0 +1,156 @@ +package love.sola.netsupport.api; + +import love.sola.netsupport.config.Settings; +import love.sola.netsupport.enums.Block; +import love.sola.netsupport.enums.ISP; +import love.sola.netsupport.pojo.User; +import love.sola.netsupport.sql.TableUser; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static love.sola.netsupport.config.Lang.lang; + +/** + * *********************************************** + * Created by Sola on 2015/11/29. + * Don't modify this source without my agreement + * *********************************************** + */ +@WebServlet(name = "Register", urlPatterns = "/api/register", loadOnStartup = 22) +public class Register extends HttpServlet { + + public static Map authorized = new ConcurrentHashMap<>(); + + public static final String STUDENT_ID_REGEX = "^(2010|2012|2013|2014|2015)[0-9]{9}$"; + public static final String PHONE_NUMBER_REGEX = "^1[34578][0-9]{9}$"; + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.setCharacterEncoding("utf-8"); + response.setCharacterEncoding("utf-8"); + response.addHeader("Content-type", "text/plain;charset=utf-8"); + PrintWriter out = response.getWriter(); + + ISP isp = checkISP(request.getParameter("isp")); + Block block = checkBlock(request.getParameter("block")); + out.println( + register( + checkStudentId(request.getParameter("sid")), + request.getParameter("name"), + isp, + checkNetAccount(request.getParameter("username"), isp), + block, + checkRoom(request.getParameter("room"), block), + checkPhoneNumber(request.getParameter("phone")), + checkWechat(request.getParameter("wechatid")) + ) + ); + out.close(); + } + + @SuppressWarnings("Duplicates") + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.setCharacterEncoding("utf-8"); + response.setCharacterEncoding("utf-8"); + response.addHeader("Content-type", "text/plain;charset=utf-8"); + PrintWriter out = response.getWriter(); + out.println(lang("Illegal_Request")); + out.close(); + } + + private String register(long sid, String name, ISP isp, String netAccount, Block block, int room, long phone, String wechat) { + if (wechat == null) return lang("Illegal_Request"); + if (sid == -1) return lang("Invalid_Student_Id"); + if (name == null) return lang("Invalid_Name"); + if (isp == null) return lang("Invalid_ISP"); + if (netAccount == null) return lang("Invalid_Account"); + if (block == null) return lang("Invalid_Block"); + if (room == -1) return lang("Invalid_Room"); + if (phone == -1) return lang("Invalid_Phone_Number"); + User user = TableUser.getUserById(sid); + if (user == null) return lang("Invalid_Student_Id"); + if (!user.getName().equals(name)) return lang("Invalid_Name"); + if (user.getWechatId() != null) return lang("User_Already_Registered"); + user.setIsp(isp); + user.setNetAccount(netAccount); + user.setBlock(block); + user.setRoom(room); + user.setPhone(phone); + user.setWechatId(wechat); + return lang("Register_Success"); + } + + + private long checkStudentId(String studentId) { + if (studentId == null) return -1; + if (studentId.matches(STUDENT_ID_REGEX)) { + try { + return Long.parseLong(studentId); + } catch (NumberFormatException ignored) { + } + } + return -1; + } + + private long checkPhoneNumber(String phone) { + if (phone == null) return -1; + if (phone.matches(PHONE_NUMBER_REGEX)) { + try { + return Long.parseLong(phone); + } catch (NumberFormatException ignored) { + } + } + return -1; + } + + private ISP checkISP(String isp) { + if (isp == null) return null; + try { + return ISP.fromId(Integer.parseInt(isp)); + } catch (NumberFormatException ignored) { + } + return null; + } + + private String checkNetAccount(String account, ISP isp) { + if (isp == null) return null; + if (account == null) return null; + if (!account.matches(isp.accountRegex)) return null; + return account; + } + + private Block checkBlock(String block) { + if (block == null) return null; + try { + return Block.fromId(Integer.parseInt(block)); + } catch (NumberFormatException ignored) { + } + return null; + } + + private int checkRoom(String room, Block block) { + if (block == null) return -1; + if (room == null) return -1; + try { + Integer i = Integer.parseInt(room); + if (i <= 100 || i >= 1300) return -1; + return i; + } catch (NumberFormatException ignored) { + } + return -1; + } + + private String checkWechat(String wechat) { + if (wechat == null) return null; + Long l = authorized.remove(wechat); + return l == null ? null : l < System.currentTimeMillis() - Settings.I.User_Register_Timeout ? null : wechat; + } + +} diff --git a/src/main/java/love/sola/netsupport/api/Response.java b/src/main/java/love/sola/netsupport/api/Response.java index 49eaad0..2b35281 100644 --- a/src/main/java/love/sola/netsupport/api/Response.java +++ b/src/main/java/love/sola/netsupport/api/Response.java @@ -5,6 +5,8 @@ import lombok.AllArgsConstructor; import java.util.HashMap; import java.util.Map; +import static love.sola.netsupport.config.Lang.lang; + /** * *********************************************** * Created by Sola on 2015/11/5. @@ -31,27 +33,26 @@ public class Response { public enum ResponseCode { - OK(0, "OK"), - PARAMETER_REQUIRED(-1, "Parameter Required"), - ILLEGAL_PARAMETER(-2, "Illegal parameter"), - USER_NOT_FOUND(-11, "User not found"), + OK(0), + PARAMETER_REQUIRED(-1), + ILLEGAL_PARAMETER(-2), + AUTHORIZE_FAILED(-9), + USER_NOT_FOUND(-11), ; private static final Map ID_MAP = new HashMap<>(); static { for (ResponseCode type : values()) { - if (type.id > 0) { - ID_MAP.put(type.id, type); - } + ID_MAP.put(type.id, type); } } public final String info; public final int id; - ResponseCode(int id, String info) { - this.info = info; + ResponseCode(int id) { + this.info = lang("RC_" + name()); this.id = id; } diff --git a/src/main/java/love/sola/netsupport/api/TestPost.java b/src/main/java/love/sola/netsupport/api/TestPost.java new file mode 100644 index 0000000..9709abb --- /dev/null +++ b/src/main/java/love/sola/netsupport/api/TestPost.java @@ -0,0 +1,44 @@ +package love.sola.netsupport.api; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Map; + +/** + * *********************************************** + * Created by Sola on 2014/8/20. + * Don't modify this source without my agreement + * *********************************************** + */ +@WebServlet(name = "TestPost",urlPatterns = "/api/testpost",loadOnStartup = 10) +public class TestPost extends HttpServlet { + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + doGet(request, response); + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.setCharacterEncoding("utf-8"); + response.setCharacterEncoding("utf-8"); + response.addHeader("Content-type", "text/plain;charset=utf-8"); + PrintWriter out = response.getWriter(); + out.println("Parameters:"); + for (Map.Entry entry : request.getParameterMap().entrySet()) { + out.println(entry.getKey() + ": " + Arrays.toString(entry.getValue())); + } + out.close(); + } + +} diff --git a/src/main/java/love/sola/netsupport/config/Lang.java b/src/main/java/love/sola/netsupport/config/Lang.java new file mode 100644 index 0000000..00c9b29 --- /dev/null +++ b/src/main/java/love/sola/netsupport/config/Lang.java @@ -0,0 +1,41 @@ +package love.sola.netsupport.config; + +import love.sola.netsupport.sql.TableLang; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * *********************************************** + * Created by Sola on 2015/11/30. + * Don't modify this source without my agreement + * *********************************************** + */ +public class Lang { + + public static Map messages; + public static Map format_cache = new HashMap<>(32); + + static { + messages = new HashMap<>(); + TableLang.getLang(messages); + } + + public static String lang(String key) { + String value = messages.get(key); + return value == null ? "!!" + key + "!!" : value; + } + + public static String format(String key, Object... args) { + MessageFormat cache = format_cache.get(key); + if (cache != null) { + return cache.format(args); + } else { + cache = new MessageFormat(lang(key)); + format_cache.put(key, cache); + return cache.format(args); + } + } + +} diff --git a/src/main/java/love/sola/netsupport/config/Settings.java b/src/main/java/love/sola/netsupport/config/Settings.java index 22c5179..06a9f89 100644 --- a/src/main/java/love/sola/netsupport/config/Settings.java +++ b/src/main/java/love/sola/netsupport/config/Settings.java @@ -29,6 +29,11 @@ public class Settings { public int Check_Spam_Cache_Expire_Time; public int Check_Spam_Interval; + public int User_Caching_Time; + + public int User_Register_Timeout; + public int User_Command_Timeout; + //No arg constructor for Yaml.loadAs public Settings() { I = this; } diff --git a/src/main/java/love/sola/netsupport/enums/Block.java b/src/main/java/love/sola/netsupport/enums/Block.java new file mode 100644 index 0000000..e6f03d2 --- /dev/null +++ b/src/main/java/love/sola/netsupport/enums/Block.java @@ -0,0 +1,106 @@ +package love.sola.netsupport.enums; + +import com.google.gson.annotations.SerializedName; + +import java.util.HashMap; +import java.util.Map; + +import static love.sola.netsupport.config.Lang.lang; + +/** + * *********************************************** + * Created by Sola on 2015/11/30. + * Don't modify this source without my agreement + * *********************************************** + */ +public enum Block { + + @SerializedName("10") + QT_18(10), + @SerializedName("11") + QT_19(11), + @SerializedName("12") + QT_16(12), + @SerializedName("13") + QT_17(13), + @SerializedName("20") + BM_7(20), + @SerializedName("21") + BM_8(21), + @SerializedName("22") + BM_9(22), + @SerializedName("23") + BM_10(23), + @SerializedName("24") + BM_11(24), + @SerializedName("30") + DM_12(30), + @SerializedName("31") + DM_13(31), + @SerializedName("32") + DM_14(32), + @SerializedName("33") + DM_15(33), + @SerializedName("40") + XH_A(40), + @SerializedName("41") + XH_B(41), + @SerializedName("42") + XH_C(42), + @SerializedName("43") + XH_D(43), + @SerializedName("50") + FX_1(50), + @SerializedName("51") + FX_2(51), + @SerializedName("52") + FX_3(52), + @SerializedName("53") + FX_4(53), + @SerializedName("54") + FX_5(54), + @SerializedName("55") + FX_6(55), + @SerializedName("60") + DM_20(60), + @SerializedName("61") + DM_21(61), + ; + + private static final Map NAME_MAP = new HashMap<>(); + private static final Map ID_MAP = new HashMap<>(); + + static { + for (Block type : values()) { + if (type.name != null) { + NAME_MAP.put(type.name.toLowerCase(), type); + } + if (type.id > 0) { + ID_MAP.put(type.id, type); + } + } + } + + public final String name; + public final int id; + + Block(int id) { + this.name = lang("BLOCK_" + name()); + this.id = id; + } + + public static Block fromName(String name) { + if (name == null) { + return null; + } + return NAME_MAP.get(name.toLowerCase()); + } + + public static Block fromId(int id) { + return ID_MAP.get(id); + } + + @Override + public String toString() { return name; } + +} diff --git a/src/main/java/love/sola/netsupport/enums/ISP.java b/src/main/java/love/sola/netsupport/enums/ISP.java new file mode 100644 index 0000000..5293988 --- /dev/null +++ b/src/main/java/love/sola/netsupport/enums/ISP.java @@ -0,0 +1,63 @@ +package love.sola.netsupport.enums; + +import com.google.gson.annotations.SerializedName; + +import java.util.HashMap; +import java.util.Map; + +import static love.sola.netsupport.config.Lang.lang; + +/** + * *********************************************** + * Created by Sola on 2014/8/20. + * Don't modify this source without my agreement + * *********************************************** + */ +public enum ISP { + + @SerializedName("1") + TELECOM(1, "^1[3|4|5|7|8][0-9]{9}$"), + @SerializedName("2") + UNICOM(2, "ZSZJLAN[0-9]{10}@16900\\.gd"), + @SerializedName("3") + CHINAMOBILE(3, "^1[3|4|5|7|8][0-9]{9}@139\\.gd$"),; + + private static final Map NAME_MAP = new HashMap<>(); + private static final Map ID_MAP = new HashMap<>(); + + static { + for (ISP type : values()) { + if (type.name != null) { + NAME_MAP.put(type.name.toLowerCase(), type); + } + if (type.id > 0) { + ID_MAP.put(type.id, type); + } + } + } + + public final int id; + public final String name; + public final String accountRegex; + + ISP(int id, String accountRegex) { + this.id = id; + this.name = lang("ISP_" + name()); + this.accountRegex = accountRegex; + } + + public static ISP fromName(String name) { + if (name == null) { + return null; + } + return NAME_MAP.get(name.toLowerCase()); + } + + public static ISP fromId(int id) { + return ID_MAP.get(id); + } + + @Override + public String toString() { return name; } + +} diff --git a/src/main/java/love/sola/netsupport/enums/ISPType.java b/src/main/java/love/sola/netsupport/enums/ISPType.java deleted file mode 100644 index 21d4e0d..0000000 --- a/src/main/java/love/sola/netsupport/enums/ISPType.java +++ /dev/null @@ -1,56 +0,0 @@ -package love.sola.netsupport.enums; - -import java.util.HashMap; -import java.util.Map; - -/** - * *********************************************** - * Created by Sola on 2014/8/20. - * Don't modify this source without my agreement - * *********************************************** - */ -public enum ISPType { - - TELECOM("Telecom", 1), - UNICOM("Unicom", 2), - CHINAMOBILE("ChinaMobile", 3),; - - private static final Map NAME_MAP = new HashMap<>(); - private static final Map ID_MAP = new HashMap<>(); - - static { - for (ISPType type : values()) { - if (type.name != null) { - NAME_MAP.put(type.name.toLowerCase(), type); - } - if (type.id > 0) { - ID_MAP.put(type.id, type); - } - } - } - - public final String name; - public final int id; - - ISPType(String name, int id) { - this.name = name; - this.id = id; - } - - public static ISPType fromName(String name) { - if (name == null) { - return null; - } - return NAME_MAP.get(name.toLowerCase()); - } - - public static ISPType fromId(int id) { - return ID_MAP.get(id); - } - - @Override - public String toString() { - return name; - } - -} diff --git a/src/main/java/love/sola/netsupport/pojo/User.java b/src/main/java/love/sola/netsupport/pojo/User.java index 74e96d0..a962faa 100644 --- a/src/main/java/love/sola/netsupport/pojo/User.java +++ b/src/main/java/love/sola/netsupport/pojo/User.java @@ -2,7 +2,8 @@ package love.sola.netsupport.pojo; import lombok.AllArgsConstructor; import lombok.Data; -import love.sola.netsupport.enums.ISPType; +import love.sola.netsupport.enums.Block; +import love.sola.netsupport.enums.ISP; /** * *********************************************** @@ -16,8 +17,11 @@ public class User { private final long id; private final String name; + private ISP isp; private String netAccount; - private ISPType isp; private String wechatId; + private Block block; + private int room; + private long phone; } diff --git a/src/main/java/love/sola/netsupport/sql/TableLang.java b/src/main/java/love/sola/netsupport/sql/TableLang.java new file mode 100644 index 0000000..d248f3a --- /dev/null +++ b/src/main/java/love/sola/netsupport/sql/TableLang.java @@ -0,0 +1,28 @@ +package love.sola.netsupport.sql; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Map; + +/** + * *********************************************** + * Created by Sola on 2015/11/30. + * Don't modify this source without my agreement + * *********************************************** + */ +public class TableLang extends SQLCore { + + public static void getLang(Map lang) { + try (Connection conn = ds.getConnection()) { + Statement st = conn.createStatement(); + ResultSet rs = st.executeQuery("SELECT * FROM lang;"); + while (rs.next()) { + lang.put(rs.getString("lkey"), rs.getString("lvalue")); + } + } catch (SQLException e) { + } + } + +} diff --git a/src/main/java/love/sola/netsupport/sql/TableUser.java b/src/main/java/love/sola/netsupport/sql/TableUser.java index b1fc2b2..ad9fc36 100644 --- a/src/main/java/love/sola/netsupport/sql/TableUser.java +++ b/src/main/java/love/sola/netsupport/sql/TableUser.java @@ -1,12 +1,19 @@ package love.sola.netsupport.sql; -import love.sola.netsupport.enums.ISPType; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import love.sola.netsupport.config.Settings; +import love.sola.netsupport.enums.Block; +import love.sola.netsupport.enums.ISP; import love.sola.netsupport.pojo.User; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; /** * *********************************************** @@ -14,43 +21,101 @@ import java.sql.SQLException; * Don't modify this source without my agreement * *********************************************** */ +@SuppressWarnings("Duplicates") public class TableUser extends SQLCore { public static final String COLUMN_ID = "id"; public static final String COLUMN_NAME = "name"; - public static final String COLUMN_NET_ACCOUNT = "netaccount"; public static final String COLUMN_ISP = "isp"; + public static final String COLUMN_NET_ACCOUNT = "netaccount"; public static final String COLUMN_WECHAT = "wechat"; + public static final String COLUMN_BLOCK = "block"; + public static final String COLUMN_ROOM = "room"; + public static final String COLUMN_PHONE = "phone"; - public static User getUserByName(String name) { - try (Connection conn = ds.getConnection()) { - PreparedStatement ps = conn.prepareStatement("SELECT * FROM user_info WHERE name=?"); - ps.setString(1, name); - ResultSet rs = ps.executeQuery(); - if (rs.next()) { - return new User(rs.getLong(COLUMN_ID), - rs.getString(COLUMN_NAME), - rs.getString(COLUMN_NET_ACCOUNT), - ISPType.fromId(rs.getInt(COLUMN_ISP)), - rs.getString(COLUMN_WECHAT)); - } - } catch (SQLException e) { - e.printStackTrace(); - } - return null; - } public static User getUserById(long id) { + if (id < 0) return null; + try { + return cache_id.get(id); + } catch (ExecutionException e) { + return null; + } + } + + public static User getUserByWechat(String wechat) { + if (wechat == null) return null; + try { + return cache_wechat.get(wechat); + } catch (ExecutionException e) { + return null; + } + } + + public static User getUserByName(String name) { + if (name == null) return null; + User u = getUserByName0(name); + if (u != null) { + cache_id.put(u.getId(), u); + if (u.getWechatId()!=null) cache_wechat.put(u.getWechatId(), u); + } + return u; + } + + public static int updateUser(User user) { + int r = updateUser0(user); + if (r > 0) { + cache_id.put(user.getId(), user); + if (user.getWechatId() != null) cache_wechat.put(user.getWechatId(), user); + } + return r; + } + + private static LoadingCache cache_id = CacheBuilder.newBuilder() + .concurrencyLevel(4) + .maximumSize(2048) + .expireAfterAccess(Settings.I.User_Caching_Time, TimeUnit.SECONDS) + .build(new IdLoader()); + + private static LoadingCache cache_wechat = CacheBuilder.newBuilder() + .concurrencyLevel(4) + .maximumSize(2048) + .expireAfterAccess(Settings.I.User_Caching_Time, TimeUnit.SECONDS) + .build(new WechatLoader()); + + + private static class IdLoader extends CacheLoader { + @Override + public User load(Long key) throws Exception { + User u = getUserById0(key); + System.out.println("Queried user: " + u); + if (u == null) throw new UserNotFoundException(); + if (u.getWechatId() != null) cache_wechat.put(u.getWechatId(), u); + return u; + } + } + + private static class WechatLoader extends CacheLoader { + @Override + public User load(String key) throws Exception { + User u = getUserByWechat0(key); + System.out.println("Queried user: " + u); + if (u == null) throw new UserNotFoundException(); + cache_id.put(u.getId(), u); + return u; + } + } + + public static class UserNotFoundException extends Exception { } + + + private static User getUserById0(long id) { try (Connection conn = ds.getConnection()) { PreparedStatement ps = conn.prepareStatement("SELECT * FROM user_info WHERE id=?"); ps.setLong(1, id); ResultSet rs = ps.executeQuery(); if (rs.next()) { - return new User(rs.getLong(COLUMN_ID), - rs.getString(COLUMN_NAME), - rs.getString(COLUMN_NET_ACCOUNT), - ISPType.fromId(rs.getInt(COLUMN_ISP)), - rs.getString(COLUMN_WECHAT)); + return constructUser(rs); } } catch (SQLException e) { e.printStackTrace(); @@ -58,21 +123,70 @@ public class TableUser extends SQLCore { return null; } - public static int updateUser(User user) { + + private static User getUserByWechat0(String wechat) { + try (Connection conn = ds.getConnection()) { + PreparedStatement ps = conn.prepareStatement("SELECT * FROM user_info WHERE wechat=?"); + ps.setString(1, wechat); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + return constructUser(rs); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + private static User getUserByName0(String name) { + try (Connection conn = ds.getConnection()) { + PreparedStatement ps = conn.prepareStatement("SELECT * FROM user_info WHERE name=?"); + ps.setString(1, name); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + return constructUser(rs); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + private static int updateUser0(User user) { try (Connection conn = ds.getConnection()) { PreparedStatement ps = conn.prepareStatement("UPDATE user_info SET " + COLUMN_WECHAT + "=?," + + COLUMN_ISP + "=?," + COLUMN_NET_ACCOUNT + "=?," + - COLUMN_ISP + "=? " + + COLUMN_BLOCK + "=?," + + COLUMN_ROOM + "=?," + + COLUMN_PHONE + "=? " + "WHERE id=?"); ps.setString(1, user.getWechatId()); - ps.setString(2, user.getNetAccount()); - ps.setInt(3, user.getIsp().id); - ps.setLong(4, user.getId()); + ps.setInt(2, user.getIsp().id); + ps.setString(3, user.getNetAccount()); + ps.setInt(4, user.getBlock().id); + ps.setInt(5, user.getRoom()); + ps.setLong(6, user.getPhone()); + ps.setLong(7, user.getId()); return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } return -1; } + + private static User constructUser(ResultSet rs) throws SQLException { + return new User( + rs.getLong(COLUMN_ID), + rs.getString(COLUMN_NAME), + ISP.fromId(rs.getInt(COLUMN_ISP)), + rs.getString(COLUMN_NET_ACCOUNT), + rs.getString(COLUMN_WECHAT), + Block.fromId(rs.getInt(COLUMN_BLOCK)), + rs.getInt(COLUMN_ROOM), + rs.getInt(COLUMN_PHONE) + ); + } + } diff --git a/src/main/java/love/sola/netsupport/wechat/Command.java b/src/main/java/love/sola/netsupport/wechat/Command.java index 548776b..a654b25 100644 --- a/src/main/java/love/sola/netsupport/wechat/Command.java +++ b/src/main/java/love/sola/netsupport/wechat/Command.java @@ -1,7 +1,5 @@ package love.sola.netsupport.wechat; -import lombok.Getter; - import java.util.HashMap; import java.util.Map; @@ -13,7 +11,7 @@ import java.util.Map; */ public enum Command { - REGISTER(0, "Register", "(?i)^Register$"), + REGISTER(0, "Register", ".*"), ; private static final Map ID_MAP = new HashMap<>(); @@ -26,12 +24,9 @@ public enum Command { } } - @Getter - private final String name; - @Getter - private final String regex; - @Getter - private final int id; + public final String name; + public final String regex; + public final int id; Command(int id, String name, String regex) { this.name = name; diff --git a/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java b/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java index 1e5a886..e4819ea 100644 --- a/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java +++ b/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java @@ -3,12 +3,11 @@ package love.sola.netsupport.wechat; import love.sola.netsupport.config.Settings; import love.sola.netsupport.wechat.handler.RegisterHandler; import love.sola.netsupport.wechat.intercepter.CheckSpamInterceptor; -import love.sola.netsupport.wechat.matcher.CommandMatcher; +import love.sola.netsupport.wechat.matcher.RegisterMatcher; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.StringUtils; -import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; -import me.chanjar.weixin.mp.api.WxMpMessageRouter; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.bean.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; @@ -18,6 +17,9 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Map; + +import static love.sola.netsupport.config.Lang.lang; /** * *********************************************** @@ -25,7 +27,7 @@ import java.io.IOException; * Don't modify this source without my agreement * *********************************************** */ -@WebServlet(name = "WxMpServlet", urlPatterns = "/wechattest", loadOnStartup = 2) +@WebServlet(name = "WxMpServlet", urlPatterns = "/wechattest", loadOnStartup = 99) public class WxMpServlet extends HttpServlet { public static WxMpServlet instance; @@ -56,10 +58,24 @@ public class WxMpServlet extends HttpServlet { wxMpMessageRouter.rule() .async(false) .msgType("text") - .matcher(new CommandMatcher(Command.REGISTER)) + .matcher(new RegisterMatcher()) .handler(new RegisterHandler()) .interceptor(checkSpamInterceptor) .end(); + wxMpMessageRouter.rule() + .async(false) + .msgType("event") + .event("subscribe") + .handler(new WxMpMessageHandler() { + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException { + return WxMpXmlOutMessage.TEXT() + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()) + .content(lang("Event_Subscribe")).build(); + } + }) + .end(); } @Override @@ -75,7 +91,7 @@ public class WxMpServlet extends HttpServlet { if (!wxMpService.checkSignature(timestamp, nonce, signature)) { // Signature fail - response.getWriter().println("Access Denied"); + response.getWriter().println(lang("Access_Denied")); return; } @@ -95,7 +111,7 @@ public class WxMpServlet extends HttpServlet { outMessage = WxMpXmlOutMessage.TEXT() .fromUser(inMessage.getToUserName()) .toUser(inMessage.getFromUserName()) - .content("Invalid Operation.") + .content(lang("Invalid_Operation")) .build(); } response.getWriter().write(outMessage.toXml()); @@ -110,14 +126,14 @@ public class WxMpServlet extends HttpServlet { outMessage = WxMpXmlOutMessage.TEXT() .fromUser(inMessage.getToUserName()) .toUser(inMessage.getFromUserName()) - .content("Invalid Operation.") + .content(lang("Invalid_Operation")) .build(); } response.getWriter().write(outMessage.toEncryptedXml(config)); return; } - response.getWriter().println("Unknown encrypt-type"); + response.getWriter().println(lang("Unknown_Encrypt_Type")); return; } diff --git a/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java b/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java index e4cf53c..7712135 100644 --- a/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java +++ b/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java @@ -1,10 +1,7 @@ package love.sola.netsupport.wechat.handler; -import love.sola.netsupport.enums.ISPType; -import love.sola.netsupport.pojo.User; -import love.sola.netsupport.sql.TableUser; +import love.sola.netsupport.api.Authorize; import love.sola.netsupport.wechat.Command; -import love.sola.netsupport.wechat.matcher.CommandMatcher; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.mp.api.WxMpMessageHandler; @@ -13,9 +10,10 @@ import me.chanjar.weixin.mp.bean.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; import me.chanjar.weixin.mp.bean.outxmlbuilder.TextBuilder; -import java.util.HashMap; import java.util.Map; +import static love.sola.netsupport.config.Lang.format; + /** * *********************************************** * Created by Sola on 2015/11/4. @@ -24,123 +22,14 @@ import java.util.Map; */ public class RegisterHandler implements WxMpMessageHandler { - public static final String STUDENT_ID_REGEX = "^(2010|2012|2013|2014|2015)[0-9]{9}"; - - Map confirmed = new HashMap<>(); - Map steps = new HashMap<>(); - @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException { TextBuilder out = WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName()); - handle(wxMessage.getContent(), wxMessage.getFromUserName(), out); + out.content(format("User_Register_Link", wxMessage.getFromUserName())); + Authorize.fetchedTime.put(wxMessage.getFromUserName(), System.currentTimeMillis()); + Authorize.fetchedCommand.put(wxMessage.getFromUserName(), Command.REGISTER); return out.build(); } - private void handle(String in, String userName, TextBuilder out) { - if (in.equalsIgnoreCase("q")) { - CommandMatcher.inCmdUsers.remove(userName); - confirmed.remove(userName); - steps.remove(userName); - out.content("Operation canceled."); - return; - } - if (!steps.containsKey(userName)) { - out.content("Welcome, please type your student identification number."); - CommandMatcher.inCmdUsers.put(userName, Command.REGISTER); - steps.put(userName, RegisterStep.STUDENT_ID); - return; - } - RegisterStep step = steps.get(userName); - if (step == RegisterStep.STUDENT_ID) { - Long sid = checkStudentId(in); - User user; - if (sid == null || (user = TableUser.getUserById(sid)) == null) { - out.content("Invalid student identification number. Type 'q' to cancel this operation."); - return; - } - out.content("Please type your real name to validate."); - confirmed.put(userName, user); - steps.put(userName, RegisterStep.NAME); - return; - } - User user = confirmed.get(userName); - if (step == RegisterStep.NAME) { - if (in.trim().equals(user.getName())) { - out.content("Confirmed success.\n" + - "Please enter your ISP.\n" + - "1-Telecom 2-Unicom 3-ChinaMobile"); - steps.put(userName, RegisterStep.ISP); - } else { - out.content("Validate failed.\n" + - "If you have any issue, please contact administrator.\n" + - "Type 'q' to cancel this operation."); - } - return; - } - if (step == RegisterStep.ISP) { - ISPType type = checkISP(in); - if (type == null) { - out.content("Invalid ISP. Please retype your ISP."); - } else { - user.setIsp(type); - out.content("Success.\n" + - "Please enter your net account."); - steps.put(userName, RegisterStep.NET_ACCOUNT); - } - return; - } - if (step == RegisterStep.NET_ACCOUNT) { - String account = checkNetAccount(in); - if (account == null) { - out.content("Invalid account. Please retype your net account."); - } else { - user.setNetAccount(account); - steps.put(userName, RegisterStep.COMPLETE); - } - } - if (step == RegisterStep.COMPLETE) { - user.setWechatId(userName); - TableUser.updateUser(user); - CommandMatcher.inCmdUsers.remove(userName); - confirmed.remove(userName); - steps.remove(userName); - out.content("Congratulations!\n" + - "You has successful registered!\n" + - "Please enjoy our service."); - } - } - - private Long checkStudentId(String studentId) { - if (studentId.matches(STUDENT_ID_REGEX)) { - try { - return Long.parseLong(studentId); - } catch (NumberFormatException ignored) { - } - } - return null; - } - - private ISPType checkISP(String isp) { - try { - return ISPType.fromId(Integer.parseInt(isp)); - } catch (NumberFormatException ignored) { - } - return null; - } - - private String checkNetAccount(String account) { - return account; - } - - enum RegisterStep { - STUDENT_ID, - NAME, - ISP, - NET_ACCOUNT, - COMPLETE, - ; - } - } diff --git a/src/main/java/love/sola/netsupport/wechat/handler/__INVALID__RegisterHandler.java b/src/main/java/love/sola/netsupport/wechat/handler/__INVALID__RegisterHandler.java new file mode 100644 index 0000000..2447d39 --- /dev/null +++ b/src/main/java/love/sola/netsupport/wechat/handler/__INVALID__RegisterHandler.java @@ -0,0 +1,146 @@ +package love.sola.netsupport.wechat.handler; + +import love.sola.netsupport.enums.ISP; +import love.sola.netsupport.pojo.User; +import love.sola.netsupport.sql.TableUser; +import love.sola.netsupport.wechat.Command; +import love.sola.netsupport.wechat.matcher.CommandMatcher; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.outxmlbuilder.TextBuilder; + +import java.util.HashMap; +import java.util.Map; + +/** + * *********************************************** + * Created by Sola on 2015/11/4. + * Don't modify this source without my agreement + * *********************************************** + */ +public class __INVALID__RegisterHandler implements WxMpMessageHandler { + + public static final String STUDENT_ID_REGEX = "^(2010|2012|2013|2014|2015)[0-9]{9}"; + + Map confirmed = new HashMap<>(); + Map steps = new HashMap<>(); + + @Override + + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) + throws WxErrorException { + TextBuilder out = WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName()); + handle(wxMessage.getContent(), wxMessage.getFromUserName(), out); + return out.build(); + } + + private void handle(String in, String userName, TextBuilder out) { + if (in.equalsIgnoreCase("q")) { + CommandMatcher.inCmdUsers.remove(userName); + confirmed.remove(userName); + steps.remove(userName); + out.content("Operation canceled."); + return; + } + if (!steps.containsKey(userName)) { + out.content("Welcome, please type your student identification number."); + CommandMatcher.inCmdUsers.put(userName, Command.REGISTER); + steps.put(userName, RegisterStep.STUDENT_ID); + return; + } + RegisterStep step = steps.get(userName); + if (step == RegisterStep.STUDENT_ID) { + Long sid = checkStudentId(in); + User user; + if (sid == null || (user = TableUser.getUserById(sid)) == null) { + out.content("Invalid student identification number. Type 'q' to cancel this operation."); + return; + } + out.content("Please type your real name to validate."); + confirmed.put(userName, user); + steps.put(userName, RegisterStep.NAME); + return; + } + User user = confirmed.get(userName); + if (step == RegisterStep.NAME) { + if (in.trim().equals(user.getName())) { + out.content("Confirmed success.\n" + + "Please enter your ISP.\n" + + "1-Telecom 2-Unicom 3-ChinaMobile"); + steps.put(userName, RegisterStep.ISP); + } else { + out.content("Validate failed.\n" + + "If you have any issue, please contact administrator.\n" + + "Type 'q' to cancel this operation."); + } + return; + } + if (step == RegisterStep.ISP) { + ISP type = checkISP(in); + if (type == null) { + out.content("Invalid ISP. Please retype your ISP."); + } else { + user.setIsp(type); + out.content("Success.\n" + + "Please enter your net account."); + steps.put(userName, RegisterStep.NET_ACCOUNT); + } + return; + } + if (step == RegisterStep.NET_ACCOUNT) { + String account = checkNetAccount(in); + if (account == null) { + out.content("Invalid account. Please retype your net account."); + } else { + user.setNetAccount(account); + steps.put(userName, step = RegisterStep.COMPLETE); + } + } + if (step == RegisterStep.COMPLETE) { + user.setWechatId(userName); + TableUser.updateUser(user); + CommandMatcher.inCmdUsers.remove(userName); + confirmed.remove(userName); + steps.remove(userName); + out.content("Congratulations!\n" + + "You has successful registered!\n" + + "Please enjoy our service."); + } + } + + private Long checkStudentId(String studentId) { + if (studentId.matches(STUDENT_ID_REGEX)) { + try { + return Long.parseLong(studentId); + } catch (NumberFormatException ignored) { + } + } + return null; + } + + private ISP checkISP(String isp) { + try { + return ISP.fromId(Integer.parseInt(isp)); + } catch (NumberFormatException ignored) { + } + return null; + } + + private String checkNetAccount(String account) { + return account; + } + + enum RegisterStep { + STUDENT_ID, + NAME, + ISP, + NET_ACCOUNT, + COMPLETE, + ; + } + +} diff --git a/src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java b/src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java index 2b3b78f..1c563ce 100644 --- a/src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java +++ b/src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java @@ -29,7 +29,7 @@ public class CommandMatcher implements WxMpMessageMatcher { if (inCmdUsers.containsKey(fromUser)) { return command == inCmdUsers.get(fromUser); } else { - return message.getContent().matches(command.getRegex()); + return message.getContent().matches(command.regex); } } diff --git a/src/main/java/love/sola/netsupport/wechat/matcher/RegisterMatcher.java b/src/main/java/love/sola/netsupport/wechat/matcher/RegisterMatcher.java new file mode 100644 index 0000000..8e2bffd --- /dev/null +++ b/src/main/java/love/sola/netsupport/wechat/matcher/RegisterMatcher.java @@ -0,0 +1,23 @@ +package love.sola.netsupport.wechat.matcher; + +import love.sola.netsupport.pojo.User; +import love.sola.netsupport.sql.TableUser; +import me.chanjar.weixin.mp.api.WxMpMessageMatcher; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; + +/** + * *********************************************** + * Created by Sola on 2015/11/26. + * Don't modify this source without my agreement + * *********************************************** + */ +public class RegisterMatcher implements WxMpMessageMatcher { + + @Override + public boolean match(WxMpXmlMessage message) { + String fromUser = message.getFromUserName(); + User u = TableUser.getUserByWechat(fromUser); + return u == null; + } + +} diff --git a/src/test/java/love/sola/netsupport/wechat/TestMessageFormat.java b/src/test/java/love/sola/netsupport/wechat/TestMessageFormat.java new file mode 100644 index 0000000..d738f5a --- /dev/null +++ b/src/test/java/love/sola/netsupport/wechat/TestMessageFormat.java @@ -0,0 +1,21 @@ +package love.sola.netsupport.wechat; + +import org.junit.Test; + +import java.text.MessageFormat; + +/** + * *********************************************** + * Created by Sola on 2015/12/2. + * Don't modify this source without my agreement + * *********************************************** + */ +public class TestMessageFormat { + + @Test + public void test() { + MessageFormat format = new MessageFormat("You''ve not registered, please CLICK HERE to register."); + System.out.println(format.format(new Object[]{"wechatid"})); + } + +}