push data structure design



According to the currently used Jiguang Push,

it is very important to design a reasonable server, and the data structure that meets all requirements is very important, but it is actually very simple.

Possible requirements: Push messages to registered users, push messages to all users, and push messages to Under such a requirement as anonymous users


, we need to save the user device did when the app starts, regardless of whether there is a login or not


. Upload mechanism : The timing of user device did upload is very important

.
The upload


data structure is as follows:



CREATE TABLE `mz_android_profile` (
  `pid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary key id, self-increasing',
  `uid` bigint(20) NOT NULL COMMENT 'userid',
  `dtype` tinyint(4) NOT NULL COMMENT 'device type 1: android phone 2: android pad',
  `did` varchar(128) NOT NULL COMMENT 'equipment unique identifier',
  `createtime` datetime NOT NULL COMMENT 'create time',
  `updatetime` datetime NOT NULL COMMENT 'update time',
  PRIMARY KEY (`pid`),
  UNIQUE KEY `AK_Key_2` (`did`),
  KEY `AK_Key_3` (`uid`,`dtype`)
) ENGINE=InnoDB AUTO_INCREMENT=1DEFAULT CHARSET=utf8 COMMENT='Push related information table'







The above is the data structure of the Android device token did, ios can also design a similar structure, such a structure can meet all the above requirements (implement your own push logic, instead of using Jiguang's background)









interface implementation:



/**
 * Android push main function
 *
 * @author sky
 * @date 2015-11-20
 */
public class AndroidPushMain {

	private static final Logger logger = LoggerFactory.getLogger(AndroidPushMain.class);

	private String appkey;
	private String appMasterSecret;

	private static AndroidPushMain instance = null;

	/**
	 * phone push client
	 */
	private static JPushClient phoneClient;
	/**
	 * Pad push client
	 */
	private static JPushClient padClient;

	private static final int maxRetryTimes = 3;// Number of reconnections

	private AndroidPushMain() {
	}

	/**
	 * Get the AndroidPushMain instance<br>
	 *
	 * singleton
	 *
	 * @return
	 */
	public static synchronized AndroidPushMain get() {

		if (instance == null) {
			instance = new AndroidPushMain();
		}
		return instance;
	}

	/**
	 * Get different jpush client according to android device type
	 *
	 * @param dtype device type, when the device type is PC, push is not supported
	 * @return
	 */
	private static JPushClient getClient(short dtype) {

		if (dtype == DeviceType.PHONE.getValue()) {
			if (phoneClient != null) {
				logger.info("android#push#getPushClient | JPush phoneClient has been instantiated, Get | dtype: {}", getDeviceTypeName(dtype));
				return phoneClient;
			}
		} else if (dtype == DeviceType.PAD.getValue()) {

			if (padClient != null) {
				logger.info("android#push#getPushClient | JPush padClient has been instantiated, Get | dtype: {}", getDeviceTypeName(dtype));
				return padClient;
			}

		} else {
			logger.error("android#push#getPushClient | Unsupported push device type PC | dtype: {}", getDeviceTypeName(dtype));
			return null;
		}

		// TODO need to cache it
		String appkey = getKey(dtype);
		String appMasterSecret = getSecret(dtype);

		if (dtype == DeviceType.PAD.getValue()) {
			padClient = new JPushClient(appMasterSecret, appkey, maxRetryTimes);
			Args.check(null != padClient, "Init AndroidJpush padClient Failure.");
			return padClient;
		} else {
			phoneClient = new JPushClient(appMasterSecret, appkey, maxRetryTimes);
			Args.check(null != phoneClient, "Init AndroidJpush phoneClient Failure.");
			return phoneClient;
		}

	}

	/**
	 * Send a message to a single user (one-to-one business, such as: a message prompt for a new order) <br>
	 * <b>Note: The type of JPush sent here is customized, can be displayed in the notification bar, and can be processed inside the APP, which is different from the message displayed only in the notification bar</b>
	 *
	 * @param uid user id
	 * @param dtype device type 1:phone 2:pad 3:pc
	 * @param msg message content
	 * @param title message title
	 * @param customFields custom data (null can be passed to indicate that there is no custom content) and the common custom data agreed by the front-end has a message type type by default using customFields.put("type",
	 * MessagePushType.DEFAULT.getValue()); Others such as message ID, msgId are not enabled yet
	 */
	public void push2One(long uid, short dtype, String msg, String title, Map<String, Object> customFields) {

		// Get the device information of the current user logged in
		Map<String, String> profile = getAndroidProfile(uid, dtype);
		if (profile == null || profile.size() <= 0) {

			logger.error("AndroidPushMain#notify | An error occurred when getting user push related information, no device information was found | uid: {}, dtype: {}", uid, dtype);
			return;
		}

		logger.info("AndroidPush#push2One | Send a message to a single user | uid: {}, dtype: {}, msg: {}, title: {}, customFields: {}", uid, dtype, msg, title,
				customFields);

		String deviceToken = profile.get("deviceToken");


		sendPush(deviceToken, title,  msg, customFields, dtype, uid);

	}

	/**
	 *
	 * The underlying sending interface
	 *
	 * @param deviceToken device unique identifier
	 * @param title message title
	 * @param msg message content
	 * @param customFields custom data (null can be passed to indicate that there is no custom content) and the common custom data agreed by the front-end has a message type type by default customFields.put("type", MessagePushType.DEFAULT.getValue());
	 * Others such as message ID, msgId are not enabled yet
	 * @param dtype device type phone, pad
	 * @param uid user uid
	 * @author sky 2016-03-11
	 */
	public void sendPush(String deviceToken, String title, String msg, Map<String, Object> customFields, short dtype, long uid) {
		// Currently sending messages through registrationId The message type is a custom type
		

		JPushClient jpushClient = getClient(dtype);

		if (jpushClient == null) {
			logger.error("AndroidPush#push2One | The obtained JPush client is empty | dtype: {}", getDeviceTypeName(dtype));
			return;
		}

		String type = "";
		Map<String, String> extras = null;

		if (MapUtils.isNotEmpty (customFields)) {

			//
			// Get the type of business that needs to be jumped: Jump to the APP home page/ Jump to the new list of merchants/ Jump to... <br>
			// The specific business type is defined in MessagePushType. The definition of the type requires the connection between the server and the client, and the scalability is not very good

			type = String.valueOf(customFields.get("type"));

			if (customFields.containsKey("params")) {
				extras = new HashMap<String, String>();
				@SuppressWarnings("unchecked")
				Map<String, Object> tmp = (Map<String, Object>) customFields.get("params");
				for (Entry<String, Object> entry : tmp.entrySet()) {
					extras.put(entry.getKey(), entry.getValue().toString());
				}
			}
		}

		PushPayload payload = (null == extras ? JPushPayloadWrapper.messageWithRegId(deviceToken, title, type, msg) : JPushPayloadWrapper
				.messageWithRegId(deviceToken, title, type, msg, extras));

		try {
			PushResult result = jpushClient.sendPush(payload);

			logger.info("AndroidPushMain#jpush | message push completed, push result | result: {}", result);

		} catch (Exception e) {

			if (e instanceof APIRequestException) {

				APIRequestException ee = (APIRequestException) e;

				logger.error(
						"AndroidPushMain#jpush | Error sending push | uid: {}, deviceToken: {}, title: {}, pushMsg: {}, httpStatus: {}, errorCode: {}, errorMsg: {}, msgId: {} ",
						uid, deviceToken, title, msg, ee.getStatus (), ee.getErrorCode (), ee.getErrorMessage (), ee.getMsgId ());

			} else if (e instanceof APIConnectionException) {
				logger.error("AndroidPushMain#jpush | 发送推送Connection error. Should retry later | uid: {}, deviceToken: {}, errorMsg: {} ",
						uid, deviceToken, e.getMessage(), e);
			}

		}
	}



	/**
	 * Get the push related information of the user's android device
	 *
	 * @param uid user id
	 * @param dtype device type 1: phone 2: pad
	 * @return
	 * @author sky
	 */
	public static Map<String, String> getAndroidProfile(long uid, short dtype) {

		try {

			String json = HttpClientUtils.doGet(CommonConstants.USER_DOMAIN + "/api/v1/deviceToken/android/queryByUidAndDtype?uid=" + uid
					+ "&dtype=" + dtype);
			RestResult<Map<String, String>> result = JsonUtils.parseObject(json, new TypeReference<RestResult<Map<String, String>>>() {
			});
			return result.getObject();

		} catch (Exception e) {

			logger.error("AndroidPushMain#getAndroidProfile | Get the user's Android device information sending error | uid: {}, dtype: {}, errorMsg: {}", uid, dtype,
					e.getMessage());

		}

		return null;
	}

	private static String getKey(short dtype) {

		return (String) EncryptionPropertyPlaceholderConfigurer.getConfig().get(getDeviceTypeName(dtype) + "_pushAppkey");

	}

	private static String getSecret(short dtype) {

		return (String) EncryptionPropertyPlaceholderConfigurer.getConfig().get(getDeviceTypeName(dtype) + "_pushAppMasterSecret");

	}

	private static String getDeviceTypeName(short dtype) {
		String type = "";
		if (dtype == DeviceType.PC.getValue())
			type = "pc";
		else if (dtype == DeviceType.PAD.getValue())
			type = "pad";
		else
			type = "phone";
		return type;
	}

	public String getAppkey() {
		return appkey;
	}

	public void setAppkey(String appkey) {
		this.appkey = appkey;
	}

	public String getAppMasterSecret() {
		return appMasterSecret;
	}

	public void setAppMasterSecret(String appMasterSecret) {
		this.appMasterSecret = appMasterSecret;
	}

}







/**
 * Local business requirement wrapper for JPush PushPayload
 *
 * @author sky
 *
 */
public class JPushPayloadWrapper {

	/**
	 * android platform
	 */
	private static final Platform Android = Platform.android();

	/**
	 * It can be displayed in the notification bar, and can be displayed in the APP (how to display is determined by the APP: when the APP is in the background, the notification bar is displayed; when the APP is in the foreground, it is displayed internally) <br>
	 * Custom message push
	 *
	 * @param regId registration id (unique identifier)
	 * @param title message title
	 * @param contentType content type, this value expresses the business type of this push, the value of contentType is defined in MessagePushType
	 * @param content message content
	 * @return
	 */
	public static PushPayload messageWithRegId(String regId, String title, String contentType, String content) {
		return PushPayload.newBuilder().//
				setAudience(Audience.registrationId(regId)).//
				setPlatform(Android).//
				setMessage(Message.newBuilder().//
						setTitle(title).//
						setContentType(contentType).//
						setMsgContent(content).//
						build()).//
				build();
	}

	/**
	 * It can be displayed in the notification bar, and can be displayed in the APP (how to display is determined by the APP: when the APP is in the background, the notification bar is displayed; when the APP is in the foreground, it is displayed internally) <br>
	 * Custom message push
	 *
	 * @param regId registration id (unique identifier)
	 * @param title message title
	 * @param contentType content type, this value expresses the business type of this push, the value of contentType is defined in MessagePushType
	 * @param content message content
	 * @param extras The attachment information body extras contains the business type data of the message: type is the key, value is the value defined in MessagePushType
	 * @return
	 */
	public static PushPayload messageWithRegId(String regId, String title, String contentType, String content, Map<String, String> extras) {
		return PushPayload.newBuilder().//
				setAudience(Audience.registrationId(regId)).//
				setPlatform(Android).//
				setMessage(Message.newBuilder().//
						setTitle(title).//
						setContentType(contentType).//
						setMsgContent(content).//
						addExtras(extras).build()).//
				build();
	}

	/**
	 * It can be displayed in the notification bar, and can be displayed in the APP (how to display is determined by the APP: when the APP is in the background, the notification bar is displayed; when the APP is in the foreground, it is displayed internally) <br>
	 * Custom message push
	 *
	 * @param alias alias
	 * @param title message title
	 * @param contentType content type, this value expresses the business type of this push, the value of contentType is defined in MessagePushType
	 * @param content message content
	 * @return
	 */
	public static PushPayload messageWithAlias(String alias, String title, String contentType, String content) {
		return PushPayload.newBuilder().setAudience(Audience.alias(alias)).//
				setPlatform(Android).//
				setMessage(Message.newBuilder().//
						setTitle(title).//
						setContentType(contentType).//
						setMsgContent(content).//

						build()).//
				build();
	}

	/**
	 *
	 * <b>Notification bar display</b><br>
	 * Broadcast message push, sent to users through tags
	 *
	 * @param tag user tag
	 * @param title message title
	 * @param content message content
	 * @param extras The attachment information body extras contains the business type data of the message: type is the key, value is the value defined in MessagePushType
	 * @return
	 */
	public static PushPayload notifyWithTag(String tag, String title, String content, Map<String, String> extras) {
		return PushPayload.newBuilder().//
				setPlatform(Android).//
				setAudience(Audience.tag(tag)).//
				setNotification(Notification.android(content, title, extras)).//
				build();
	}

	/**
	 * <b>Notification bar display</b><br>
	 * Broadcast message push, sent to users through aliases
	 *
	 * @param alias alias
	 * @param title message title
	 * @param content message content
	 * @param extras Extras contain the business type data of the message: type is the key, value is the value defined in MessagePushType
	 * @return
	 */
	public static PushPayload notifyWithAlias(String alias, String title, String content, Map<String, String> extras) {
		return PushPayload.newBuilder().//
				setPlatform(Android).//
				setAudience(Audience.alias(alias)).//
				setNotification(Notification.android(content, title, extras)).//
				build();

	}

	/**
	 * <b>Notification bar display</b><br>
	 * Broadcast message push, sent to users by registering deviceToken
	 *
	 * @param regId registration id (unique identifier)
	 * @param title message title
	 * @param content message content
	 * @param extras Extras contain the business type data of the message: type is the key, value is the value defined in MessagePushType
	 * @return
	 */
	public static PushPayload notifyWithRegId(String regId, String title, String content, Map<String, String> extras) {
		return PushPayload.newBuilder().//
				setPlatform(Android).//
				setAudience(Audience.registrationId(regId)).//
				setNotification(Notification.android(content, title, extras)).//
				build();
	}

	/**
	 * <b>Notification bar display</b><br>
	 * Broadcast message push
	 *
	 * @param content message content
	 * @return
	 */
	public static PushPayload notifyAll(String content) {
		return PushPayload.alertAll(content);
	}

}







Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326988416&siteId=291194637