Este artigo é a segunda parte do envio de mensagens de texto. Aqui, introduzimos como limitar a frequência de enviar mensagens de texto para o mesmo usuário (com base no número de telefone celular e IP).
1. Usar sessão
Se for um programa da Web, também é possível gravar a última vez que a sessão, mas pode ser ignorada. O mais simples é reiniciar diretamente o navegador ou limpar o cache e outros dados que podem marcar a sessão, para que os registros na sessão possam ser ignorados. Embora muitas pessoas não sejam profissionais em computadores e não as tenham aprendido. Mas precisamos observar que o motivo para limitar a frequência de envio é evitar "bombas de SMS", ou seja, alguém solicita maliciosamente e freqüentemente para enviar mensagens de texto para um número de telefone celular. Portanto, essa pessoa pode entender esse conhecimento.
Em seguida, usamos o limite de dados "global" para enviar frequência ao mesmo usuário. Vamos fazer algum trabalho de "preparação" primeiro.
2. Defina interfaces e classes de entidade
As classes de entidade que precisamos são as seguintes:
Smsentity.java
classe pública smsentity {private integer id; String privado móvel; private string ip; tipo inteiro privado; data de data particular; Captcha privada de string; // omita o método do construtor e métodos getter e setter}A interface de filtragem é a seguinte:
Smsfilter.java
interface pública smsfilter { / *** inicialize o filtro* / void init () lança exceção; /*** Determine se a mensagem de texto pode ser enviada. * @param smsentity O conteúdo da mensagem de texto a ser enviado * @return Se ele puder ser enviado, ele retornará verdadeiro, caso contrário, retornará filtro falso */ booleano (smsentity smsentity); / *** Destrua o filtro*/ void Destroy ();}3. Código principal
Para limitar a frequência do envio, você precisa gravar um determinado número de telefone celular (IP) e a hora da última vez que enviou uma mensagem de texto. É muito adequado para a conclusão do mapa. Aqui, primeiro usamos o ConcurrentMap para implementá -lo:
FrequencyFilter.java
public class FrequencyFilter implementa SMSFilter { / *** Enviar intervalo, unidade: milissegundos* / private Long SendInterval; private concorrentemap <string, long> sendAddressMap = new ConcurrentHashMap <> (); // Algum código inútil omitido @Override public boolean filtro (smsentity smsentity) {if (setSendtime (smSentity.getMobile ()) && SetSendTime (smSentity.getip ())) {return true; } retornar false; } /*** Modifique o tempo de envio para a hora atual. * Se o intervalo de tempo do último enviado for maior que {@link #sendInterval}, defina o tempo de envio para a hora atual. Caso contrário, nenhum conteúdo será modificado. * * @param ID Envie o número do celular ou IP * @return Se o tempo de envio for modificado com sucesso para o horário atual, ele retornará true. Caso contrário, ele retornará 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); }}Aqui, a lógica principal é implementada no método SetSendTime :
Linhas 25-28: Primeiro, assumindo que o usuário envie um SMS pela primeira vez, a hora atual deve ser colocada no sendAddressMap. Se o Putifabsent retorna nulo, significa que o usuário está realmente enviando um SMS pela primeira vez, e o horário atual foi colocado no mapa e pode ser enviado.
Linhas 30-33: Se o usuário não estiver enviando um SMS pela primeira vez, será necessário determinar se o tempo e o intervalo atual de envio do SMS da última vez e o intervalo de tempo são menores que o intervalo de tempo de envio. Se for menor que o intervalo de tempo de envio, não poderá ser enviado.
Linha 35: Se o intervalo de tempo for grande o suficiente, você precisará tentar definir o tempo de envio para o horário atual.
1) Então você pode repetir as linhas 25-35 para garantir que elas estejam absolutamente corretas.
2) Você também pode pensar diretamente que ele não pode ser enviado, porque, embora o tempo teórico para "a execução das linhas 26-35" possa ser maior que o "intervalo de envio", quanto é a probabilidade? Pode basicamente ser ignorado.
Esse código implementa a limitação de frequência, mas se houver apenas "em", mas não "fora", o conteúdo ocupado pelo SendAddressMap se tornará cada vez maior até que uma exceção ou exceção do MemoryError seja gerada. Em seguida, adicionaremos o código para limpar os dados expirados regularmente.
4. Limpe os dados expirados
FrequencyFilter.java
/*** Com base no código acima, adicione o seguinte código*/public class FrequencyFilter implementa SMSFilter {Private Long CleanMapInterval; Timer privado Timer = new Timer ("SMS_FREQUENCY_FILTER_CLEAR_DATA_THREAD"); @Override public void init () {timer.schedule (new timerTask () {@Override public void run () {cleanSendAdDressMap ();}}, limpoMapInterval, limpezaMapInterval); } / *** Exclua todos os dados expirados no sendAddressMap* / private void cleanSendAddressMap () {long curntime = system.currenttimemillis (); long expiresendTime = CurrentTime - sendInterval; para (chave de string: sendAddressMap.KeySet ()) {long SendTime = sendAddressMap.get (key); if (sendtime <expiresendtime) {sendAddressmap.remove (chave, sendtime); }}} @Override public void Destroy () {timer.cancel (); }}Este programa não é complicado. Inicie um cronômetro e execute o método CleaSendAddressMap todos os milissegundos do limpo MapInterval para limpar os dados vencidos.
O método CleaSendAddressMap primeiro obtém o horário atual e obtém um valor de tempo com base no horário atual: todas as mensagens de texto são enviadas após esse período, o SMS não pode ser enviado novamente. Em seguida, exclua todos os pares de valor-chave com valor menor que esse valor de tempo de todo o mapa.
Obviamente, depois de adicionar o código acima, o código inicial tem outro bug: quando a última linha sendAddressmap.Replace (ID, SendTime, CurrentTime) falha ao executar, não é necessariamente que outros threads tenham sido substituídos, mas também é possível que o encadeamento de limpeza tenha excluído os dados. Portanto, precisamos modificar as últimas linhas do método SetSendTime:
FrequencyFilter.java
private boolean setSendtime (string id) {// omita o código anterior if (sendAddressMap.replace (id, sendtime, currentTime)) {return true; } retornar sendAddressMap.putifabsent (id, currenttime) == null;}Se a substituição for bem -sucedida aqui, retorne diretamente diretamente.
Se a substituição não for bem -sucedida, pode ser que outros threads tenham sido substituídos primeiro (no primeiro caso); Também pode ser que eles tenham sido excluídos pelo fio limpo (no segundo caso); Pode até ser que eles tenham sido excluídos primeiro pelo thread limpo e outros threads inseriram novos valores de tempo (no terceiro caso).
Neste ponto, o código que limita o tempo de envio é concluído. Obviamente, este programa tem um pequeno bug ou "recurso":
Se um cliente com IP "192.168.0.1" solicitar uma mensagem de texto para o número de telefone celular "12345678900", e depois solicitar para enviar uma mensagem de texto para o número do celular "12345678900" dentro do sendInterval na máquina com IP "192.168.0.2". Em seguida, a mensagem de texto não será enviada e, na última vez em que o número de telefone celular "12345678900" é definido na hora atual.
5. Exemplos de uso
Abaixo, fornecemos uma camada de servidor para mostrar como integrar o código no artigo anterior e este artigo:
Smsservice.java
classe pública SMSSERVICE {private SMS SMS; Lista privada <Msfilter> filtros; modelo de propriedades privadas; // Alguns códigos são omitidos/*** Enviar código de verificação** @param smsentity Dados básicos para enviar mensagens de texto* @return Se o envio for bem -sucedido, retorne 0. Caso contrário, retorne outros valores. */ public int sendCaptcha (smsentity smsentity) {for (filtro smsfilter: filtros) {if (! filter.filter (smSentity)) {return 1; }} if (smsentity.register_type.equals (smSentity.getType ())) {sendRorGistersMs (smsentity); } else {return 2; } retornar 0; } / *** Envie o código de verificação de registro** @param smsentity dados básicos para enviar mensagens de texto* / private void sendRorGistersms (smsentity smsentity) {sms.sendMessage (smsentity.getMobile (), model.getProperty ("registro"). }}Em seguida, "Injetar" FrequencyFilter e AsyncsmsImpl no artigo anterior através do método set.
O exposto acima é tudo sobre este artigo, espero que seja útil para todos aprenderem a programação Java.