Cet article est la deuxième partie de l'envoi de messages texte. Ici, nous introduisons comment limiter la fréquence d'envoi de messages texte au même utilisateur (en fonction du numéro de téléphone mobile et de l'IP).
1. Utiliser la session
S'il s'agit d'un programme Web, il est également possible d'enregistrer la dernière fois envoyé dans la session, mais il peut être contourné. La chose la plus simple est de redémarrer directement le navigateur ou le cache effacer et d'autres données qui peuvent marquer la session, de sorte que les enregistrements de la session peuvent être contournés. Bien que beaucoup de gens ne soient pas professionnels dans les ordinateurs et ne les ont pas appris. Mais nous devons noter que la raison de la limitation de la fréquence d'envoi est d'empêcher les "bombes SMS", c'est-à-dire une personne de manière malveillante et fréquente pour envoyer des SMS à un numéro de téléphone portable. Par conséquent, cette personne peut comprendre ces connaissances.
Ensuite, nous utilisons la limite de données "globale" pour envoyer la fréquence au même utilisateur. Faisons d'abord un peu de "préparation".
2. Définir les interfaces et les cours d'entité
Les cours d'entités dont nous avons besoin sont les suivants:
SmSentity.java
classe publique SmSentity {ID entier privé; Mobile de chaîne privée; chaîne privée ip; type entier privé; heure privée de date; Captcha à cordes privées; // omettez la méthode du constructeur et les méthodes Getter et Setter}L'interface de filtrage est la suivante:
Smsfilter.java
Interface publique SmsFilter {/ ** * Initialiser le filtre * / void init () lève une exception; / ** * Déterminez si le SMS peut être envoyé. * @param smSentity Le contenu du SMS à envoyer * @return s'il peut être envoyé, il renverra vrai, sinon il renverra False * / booléen filtre (SmSentity smSentity); / ** * Détruisez le filtre * / void destroy ();}3. Code principal
Pour limiter la fréquence d'envoi, vous devez enregistrer un certain numéro de téléphone mobile (IP) et l'heure de la dernière fois que vous avez envoyé un SMS. Il est très adapté à la carte de la carte. Ici, nous utilisons d'abord concurrentmap pour l'implémenter:
Fréquencefilter.java
Classe publique FrequencyFilter implémente SmsFilter {/ ** * Envoi Interval, unité: millisecondes * / private long Sendinterval; privé concurrentmap <string, long> sendAddressMap = new concurrenthashmap <> (); // un code inutile omis @Override public booléan filter (smSentity smSentity) {if (setSendTime (smSentity.getMobile ()) && setSendTime (smSentity.GetIp ())) {return true; } return false; } / ** * Modifiez le temps d'envoi à l'heure actuelle. * Si l'intervalle de temps du dernier envoyé est supérieur à {@link #SendInterval}, définissez le temps d'envoi à l'heure actuelle. Sinon, aucun contenu ne sera modifié. * * @param id Envoyer un numéro de mobile ou IP * @return Si l'heure d'envoi est modifiée avec succès à l'heure actuelle, il reviendra vrai. Sinon, il renverra false * / private boolean setSendTime (String id) {long currentTime = System.currentTimeMillis (); Long SendTime = SendAddressMap.PUTIFABSENT (ID, CurrentTime); if (SendTime == null) {return true; } long nextCanSendTime = Sendtime + sendInterval; if (currenttime <nextCanSendTime) {return false; } return SendAddressMap.replace (id, Sendtime, CurrentTime); }}Ici, la logique principale est implémentée dans la méthode SetSendTime :
Lignes 25-28: Tout d'abord, en supposant que l'utilisateur envoie un SMS pour la première fois, l'heure actuelle doit être placée dans le SendAddressMap. Si Putifabsent renvoie NULL, cela signifie que l'utilisateur envoie effectivement un SMS pour la première fois et que l'heure actuelle a été mise sur la carte, et elle peut être envoyée.
Lignes 30-33: Si l'utilisateur n'envoie pas de SMS pour la première fois, il est nécessaire de déterminer si l'intervalle de temps et de courant de l'envoi du SMS la dernière fois et que l'intervalle de temps est inférieur à l'intervalle de temps d'envoi. S'il est inférieur à l'intervalle d'envoi de temps, il ne peut pas être envoyé.
Ligne 35: Si l'intervalle de temps est suffisamment grand, vous devez essayer de définir le temps d'envoi à l'heure actuelle.
1) Ensuite, vous pouvez répéter les lignes 25-35 pour vous assurer qu'elles sont absolument correctes.
2) Vous pouvez également penser directement qu'il ne peut pas être envoyé, car bien que le temps théorique de "l'exécution des lignes 26-35" puisse être supérieur à l'intervalle d'envoi, quelle est la probabilité? Il peut être ignoré.
Ce code met en œuvre la limitation de fréquence, mais s'il n'y a que "dans" mais pas "out", alors le contenu occupé par SendAddressMap deviendra de plus en plus grand jusqu'à ce qu'une exception OutOfMemoryError soit générée. Ensuite, nous ajouterons le code pour nettoyer régulièrement les données expirées.
4. Nettoyer les données expirées
Fréquencefilter.java
/ ** * En fonction du code ci-dessus, ajoutez le code suivant * / classe publique FréquenceFilter implémente SMSFilter {private long CleanMapInterval; Timer timer privé = new Timer ("SMS_FREQUENCY_FILTER_CLEAR_DATA_THREAD"); @Override public void init () {timer.schedule (new Timemertask () {@Override public void run () {CleanSendAddressMap ();}}, CleanMapInterval, CleanMapInterval); } / ** * Supprimer toutes les données expirées dans SendAddressMap * / private void CleanSendAddressMap () {long currentTime = System.currentTimemillis (); long expireSendTime = currentTime - sendInterval; For (String Key: SendAddressMap.KeySet ()) {Long SendTime = SendAddressMap.get (key); if (SendTime <exireSendTime) {SendAddressMap.Remove (Key, Sendtime); }}} @Override public void destren () {timer.cancel (); }}Ce programme n'est pas compliqué. Démarrez une minuterie et exécutez la méthode CleanSendAddressMap toutes les millisecondes de CleanMapInterval pour nettoyer les données expirées.
La méthode CleanSendAddressMap obtient d'abord l'heure actuelle et obtient une valeur de temps basée sur l'heure actuelle: tous les messages texte sont envoyés après cette heure, les SMS ne peuvent pas être envoyés à nouveau. Supprimez ensuite toutes les paires de valeurs clés avec une valeur inférieure à cette valeur de temps de toute la carte.
Bien sûr, après avoir ajouté le code ci-dessus, le code initial a un autre bogue: lorsque la dernière ligne SendAddressMap.replace (ID, Sendtime, CurrentTime) ne parvient pas, il n'est pas nécessairement que d'autres threads aient été remplacés, mais il est également possible que le thread de nettoyage ait supprimé les données. Nous devons donc modifier les dernières lignes de la méthode SetSendTime:
Fréquencefilter.java
Boolean privé setSendTime (String id) {// omettre le code précédent if (sendAddressMap.replace (id, sendtime, currenttime)) {return true; } return SendAddressMap.PUTIFABSENT (ID, CurrentTime) == NULL;}Si le remplacement réussit ici, revenez vrai directement.
Si le remplacement n'est pas réussi, il se peut que d'autres threads aient été remplacés en premier (dans le premier cas); Il se peut également qu'ils aient été supprimés par le fil nettoyé (dans le deuxième cas); Il se peut même qu'ils aient d'abord été supprimés par le fil nettoyé, et d'autres threads ont inséré de nouvelles valeurs de temps (dans le troisième cas).
À ce stade, le code qui limite l'heure d'envoi est terminé. Bien sûr, ce programme a un petit bug ou une "fonctionnalité":
Si un client avec IP "192.168.0.1" demande d'envoyer un SMS au numéro de téléphone mobile "12345678900", puis demande d'envoyer un SMS au numéro de téléphone mobile "12345678900" dans Sendinterval sur la machine avec IP "192.168.0.2". Ensuite, le SMS ne sera pas envoyé, et la dernière fois du numéro de téléphone mobile "12345678900" est défini à l'heure actuelle.
5. Exemples d'utilisation
Ci-dessous, nous fournissons une couche de serveur pour montrer comment intégrer le code dans l'article précédent et cet article:
Smsservice.java
classe publique SMSService {SMS privé SMS; Liste privée <smsFilter> Filtres; modèle de propriétés privées; // Certains codes sont omis / ** * Envoyer le code de vérification * * @param smSentity Data Basic pour envoyer des messages texte * @return Si la soumission est réussie, renvoyez 0. Sinon, renvoyez d'autres valeurs. * / public int sendCaptCha (smSentity smSentity) {for (smsfilter filter: filters) {if (! filter.filter (smSentity)) {return 1; }} if (smSentity.register_type.equals (smSentity.getType ())) {sendRegistersms (smSentity); } else {return 2; } return 0; } / ** * Envoi du code de vérification d'enregistrement * * @param smSentity Data Basic pour envoyer des messages texte * / private void sendRegistersms (smSentity smSentity) {sms.sendMessage (smSentity.getMobile (), template.getProperty ("registre"). Remplace ("{captCha}", smssentity.getcaptcha ())); }}Ensuite, "Inject" Frequencyfilter et AsyncSMSIMP dans l'article précédent via la méthode SET.
Ce qui précède concerne cet article, j'espère qu'il sera utile pour tout le monde d'apprendre la programmation Java.