Делаю бота для Telegram на Java. При разработке столкнулся с тем, что система хранит где-то объект и отправляет его параметры несмотря на то, что объект пересоздан.
Как это должно работать
1. Пользователь что-то пишет боту
2. Бот получает из класса Main - HashMap с объектами User, где ключ - уникальный идентификатор пользователя внутри Telegram.
3. Если данных в HashMap по пользователю нет - бот создаёт экземпляр класса User()
3.1 Конструктор в User делает запрос к базе данных и сохраняет в переменных все значения (nickname, id, TelegramID и так далее).
4. Вызывается метод isRegister() класса User, который проверяет заполнился ли объект конструктором и если нет, то пользователь не зарегистрирован. Если да - сохраняет экземпляр класса в HashMap
5. Отправляется в ответ сообщение о том что пользователь: зарегистрирован / не зарегистрирован
Как это работает сейчас
1. Пользователь что-то пишет боту
2. Бот проверяет есть ли данные в HashMap (их нет, потому что программа пока не сохраняет их там)
3. Бот создаёт экземпляр класса User и заполняет его данными из базы конструктором
4. Если экземпляр пуст, то пишет что пользователь не зарегистрирован. Если заполнен - пишет что зарегистрирован
5. Если пользователь не зарегистрирован, при попытке что-то написать, каждый раз выводится сообщение что юзер не зарегистрирован.
6. Создаём в базе данных запись с данными пользователя
7. Пишем боту и он отвечает что пользователь зарегистрирован
8. Меняем идентификатор пользователя в базе на любой другой
9. Бот до сих пор пишет что пользователь зарегистрирован и выводит данные ранее заполненного объекта User. Даже если боту написать с другого аккаунта - всё равно выводит данные первого аккаунта
Не совсем понятно где сохраняется объект User и почему сохраняется, когда каждый раз должен создаваться заново и заново наполняться или быть пустым (если данных нет).
Код
Core
package org.teateam.Chat;
import org.teateam.Main;
import org.teateam.TelegramApi;
import org.teateam.User;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
public class Core extends Thread{
@Override
public void run(){
System.out.println("Chat flow started");
// Telegram startup section
Main.telegramApi = new TelegramApi();
TelegramBotsApi botsApi = new TelegramBotsApi();
try {
botsApi.registerBot(Main.telegramApi);
}
catch (TelegramApiException ex){
ex.printStackTrace();
}
// End section
}
public static void validateText(String text, long from_id) {
User user = Main.users.get(from_id);
if(user == null){
// If not online
user = new User(from_id);
if(user.isRegister()) {
Main.telegramApi.sendTextMessage(from_id, "Вы зарегистрированы. Nickname: " + user.nickname + ". Tid: " + user.tid);
}
else{
Main.telegramApi.sendTextMessage(from_id, "Вы не зарегистрированы");
}
}
else{
Main.telegramApi.sendTextMessage(from_id, "Your nick is " + user.nickname);
}
}
}
Обрабатывает новые события в методе validateText(), пришедшие от метода onUpdateReceived() в классе TelegramApi
TelegramApi
package org.teateam;
import org.teateam.Chat.Core;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
public class TelegramApi extends TelegramLongPollingBot {
private SendMessage message = new SendMessage();
public TelegramApi(){
System.out.println("Bot has been started success");
}
public void sendTextMessage(long peer_id, String text){
this.message.setChatId(peer_id).setText(text);
try {
execute(this.message);
}
catch (TelegramApiException tEx){
System.out.println("Exception in org.teateam.TelegramApi: " + tEx);
}
}
@Override
public void onUpdateReceived(Update update) {
if(update.hasMessage() && update.getMessage().hasText()){
// If text
Core.validateText(update.getMessage().getText(), update.getMessage().getChatId());
System.out.println(" ");
System.out.println("New message: " + update.getMessage().getText());
System.out.println("From ID: " + update.getMessage().getChatId());
System.gc();
}
}
@Override
public String getBotUsername() {
return Main.getBotUsername();
}
@Override
public String getBotToken() {
return Main.getAccess_token();
}
}
validateText() проверяет есть ли объект User в HashMap (его всегда нет в данной реализации) и создаёт объект класса User.
User
package org.teateam;
import java.util.ArrayList;
public class User {
public long tid;
public String nickname;
public int accessLevel;
public int id;
public boolean online;
public int room;
public User(long tid){
// Add data from database
String query = "SELECT * FROM `users` WHERE `tid` = '" + tid + "' LIMIT 1;";
ArrayList<String> result = MySQL.select(query);
if(!result.isEmpty()) {
this.tid = Long.parseLong(result.get(0));
this.nickname = result.get(1);
this.accessLevel = Integer.parseInt(result.get(2));
this.id = Integer.parseInt(result.get(3));
this.online = false;
this.room = 0;
}
}
public boolean isRegister(){
return this.nickname != null;
}
}
User, при создании, делает запрос к базе через метод select() класса MySQL и получает от него ArrayList, которым заполняет самого себя. Если MySQL возвращает пустой ArrayList, то экземпляр класса не заполняется.
MySQL
package org.teateam;
import java.sql.*;
import java.util.ArrayList;
public class MySQL {
private static final String host = "";
private static final int port = 3306;
private static final String user = "";
private static final String password = "";
private static final String database = "";
private static final String url = "jdbc:mysql://" + host + ":" + port + "/" + database + "?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static Connection connection;
private static Statement statement;
private static ResultSet resultSet;
private static ResultSetMetaData resultSetMetaData;
private static ArrayList<String> result = new ArrayList<>();
/**
*
* @param query For example: SELECT `login` FROM `users` WHERE `id` = 1 LIMIT 1;
* @return ArrayList<String>
*/
public static ArrayList<String> select(String query){
try{
connection = DriverManager.getConnection(url, user, password);
statement = connection.createStatement();
resultSet = statement.executeQuery(query);
resultSetMetaData = resultSet.getMetaData();
try {
while (resultSet.next()) {
for(int i = 0; i < resultSetMetaData.getColumnCount(); i++){
result.add(resultSet.getString(i + 1 ));
System.out.println(resultSet.getString(i + 1));
}
}
}
catch (SQLException sqlEx){
sqlEx.printStackTrace();
return result;
}
}
catch (SQLException sqlEx){
sqlEx.printStackTrace();
}
finally {
try{ connection.close(); } catch (SQLException se) { /* TODO anything */ se.printStackTrace();}
try{ statement.close(); } catch (SQLException se) { /* TODO anything */ se.printStackTrace();}
try{ resultSet.close(); } catch (SQLException se) { /* TODO anything */ se.printStackTrace();}
}
return result;
}
}
В классе MySQL есть private static ArrayList result, который хранит значения. В случае, если данные есть в базе - он наполняется и потом возвращается в User. В случае, если данных нет в базе, но до этого этот объект User уже вызывался- с result ничего не происходит и он возвращается с последним значением. Собственно, result и хранил в себе все данные, по которым заполнялся User и не переопределялся в конце.
Решено добавлением следующей строки в начале метода select() класса MySQL:
result.clear();
Что позволяет каждый раз очищать ArrayList от последнего запроса.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Вводится из консоли дата (тип String)При посимвольном сравнении, на второй вводимой дате вылетает ошибка java
Требуется алгоритм который бы вытащил >3 <6 значное число из строки
Читаю книгу по паттернам (паттерны проектирования, Эрик и Элизабет Фримен42 ст