Android взаимодействует с серверной базой данных через Интернет.

Android

2021.1.27 Обновить

Новая версия блога была обновлена, и обновленный контент немного больше, чем исходная статья, поэтому был открыт новый блог, пожалуйстакликните сюда.

1. Предпосылки

разрабатыватьAppВзаимодействие с серверной базой данных на основеMySQL+ роднойJDBC+Tomcat,не использовалDBUtilsилиJDBCкаркас, чистое дноJDBCвыполнить.

За последние несколько дней я наступил на много ям. Если преувеличить, я действительно наступил без чувств. Надеюсь, это поможет читателям меньше наступать на ямы...

2 Среда разработки

  • Windows10
  • серверCentOS 7
  • Android Studio 3.5.1
  • IntelliJ IDEA 2019.02
  • MySQL 8.0.17
  • Tomcat 9.0.26

3 Подготовьте среду

в основном установитьMySQLа такжеTomcat, уже установленные можно пропустить.

3.1 УстановкаMySQL

Это относительно новыйMySQLВерсия.

Серверная системаCentOS.

См. здесь для других системных установок:

CentOSиспользоватьyumПросто установите его.

3.1.1 Загрузите и установитеMySQL

sudo yum localinstall https://repo.mysql.com//mysql80-community-release-el7-1.noarch.rpm
sudo yum install mysql-community-server

3.1.2 Запустите службу и просмотрите пароль инициализации

sudo service mysqld start
sudo grep 'temporary password' /var/log/mysqld.log

3.1.3 Изменить пароль

Сначала войдите в систему с правами root:

mysql -u root -p

Введите пароль, который вы видели на предыдущем шаге, затем используйтеalterизменить пароль:

alter mysql.user 'root'@'localhost' identified by 'password';

Обратите внимание на новую версиюMySQLНе используйте слабые пароли, такие как:

在这里插入图片描述Если появляется это сообщение, пароль слишком слабый, используйте более надежный пароль.

3.1.4 Разрешить внешний доступ

use mysql;
update user set host='%' where user='root';

Это может быть изменено в соответствии с вашими потребностями,host='%'разрешить всеipлогин, вы также можете установить конкретныйip, если использоватьhost='%'В этом случае рекомендуется создать нового пользователя для настройки соответствующих разрешений.

3.1.5 Настройка брандмауэра (необязательно)

Вообще говоря, вам нужно открыть порт ответа в конфигурации брандмауэра соответствующего поставщика облака, как показано на рисунке:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Авторизованные объекты могут быть изменены в соответствии с их собственными потребностями,0.0.0.0/0разрешить всеip.

3.2 УстановкаTomcat

3.2.1 Загрузка и загрузка на сервер

иди первыйОфициальный сайтСкачать, загрузить файл на сервер после скачивания:

在这里插入图片描述

在这里插入图片描述

Автор используетscpЗаказ,Если вы не квалифицированы, вы можете нажать здесь, чтобы увидеть:

scp apache-tomcat-xxxx.tar.gz username@xx.xx.xx.xx:/

изменить свое имя пользователя иip.

3.2.2 Декомпрессия

sshподключитесь к серверу, затем перейдите к/usr/localи распакуйте его:

mkdir /usr/local/tomcat
mv apache-tomcat-xxxx.tar.gz /usr/local/tomcat
tar -xzvf apache-tomcat-xxx.tar.gz

3.2.3 Изменить порт по умолчанию (необязательно)

Исправлятьconf/server.xmlфайл, как правило, нужно только изменить

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

середина8080порт, вы можете изменить этот порт.

При необходимости измените его.

3.2.4 Запуск

бегатьbinв каталогеstartup.sh:

cd bin
./startup.sh

3.2.5 Тест

Вход через браузер:

服务器IP:端口

Если появится:

在这里插入图片描述

указывает на успех.

3.2.6 Запуск (необязательно)

Рекомендуется настроить запуск и изменить/etc/rc.localфайл, добавьте:

sh /usr/local/tomcat/bin/startup.sh

Это основано на вашем собственномTomcatИзменение пути установки, указатьbinвнизstartup.sh.

4 Создание базы данных и построение таблицы

Создайте таблицу пользователей и упростите здесь операцию, не создавая нового пользователя и не авторизуя его.

это местныйrootДля примера входа создайте и авторизуйте пользователей в соответствии с реальной ситуацией.

4.1 Пользовательская таблица

CREATE DATABASE userinfo;
USE userinfo;
CREATE TABLE user
(
    id          INT     NOT NULL    PRIMARY KEY   AUTO_INCREMENT,
    name        CHAR(30)    NULL,
    password    CHAR(30)    NULL
);

4.2 Импорт

mysql -u root -p < user.sql

在这里插入图片描述

Таким образом, подготовительная работа завершена, и этап кодирования официально начинается ниже.

5 Задняя часть

5.1 Создать проект

выберитеWeb Application: 在这里插入图片描述

在这里插入图片描述

5.2 Добавить библиотеку зависимостей

создатьlibКаталог:在这里插入图片描述

добавить дваJARПакет (ссылка для скачивания указана в конце статьи):

  • mysql-connector-java-8.0.17.jar
  • javax.servlet-api-4.0.1.jar

在这里插入图片描述

ОткрытьProject Structure:

在这里插入图片描述

Modules --> + --> JARs or directories:

在这里插入图片描述

Выберите только что созданныйlibследующие дваJARСумка:

在这里插入图片描述

отметьте иapply:

在这里插入图片描述

5.3 Создание пакетов и классов

Всего 4 упаковки:

  • com.servlet: используется для обработки запросов от внешнего интерфейса, включаяSignUp.java,SignIn.java
  • com.util: Основная функция — подключение к базе данных, в т.ч.DBUtils.java
  • com.entity: класс сущности, содержащийUser.java
  • com.dao: Класс, управляющий пользовательским классом, включаяUserDao.java

在这里插入图片描述

5.4 DBUtils

Класс, который подключается к базе данных, чистый нижний слойJDBCвыполнить,Обратите внимание на версию драйвера.

public class DBUtils {

    private static Connection connection = null;
    public static Connection getConnection()
    {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/数据库名字";
            String usename = "账号";
            String password = "密码";
            connection = DriverManager.getConnection(url,usename,password);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return null;
        }
        return connection;
    }

    public static void closeConnection()
    {
        if(connection != null)
        {
            try {
                connection.close();
            }
            catch (SQLException e)
            {
                e.printStackTrace();
            }
        }
    }
}

Основная функция - получить соединение и закрыть соединение.

String url = "jdbc:mysql://127.0.0.1:3306/数据库名字";
String usename = "账号";
String password = "密码";

Эти строки основаны на их имени пользователя, пароле, сервереipи изменение имени библиотеки.

Обратите внимание, что оператор регистра драйвера, используемый в MySQL 8.0 и выше,:

Class.forName("com.mysql.cj.jdbc.Driver");

Старая версия:

Class.forName("com.mysql.jdbc.Driver");

5.5 User

UserКласс относительно прост, то есть три поля иGetter+Setter.

public class User {
    private int id;
    private String name;
    private String password;
    //三个Getter与三个Setter
    //...
}

5.6 UserDao

public class UserDao {
    public boolean query(User user)
    {
        Connection connection = DBUtils.getConnection();
        String sql = "select * from user where name = ? and password = ?";
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,user.getName());
            preparedStatement.setString(2,user.getPassword());
            ResultSet resultSet = preparedStatement.executeQuery();
            return resultSet.next();
        }
        catch (SQLException e)
        {
            e.printStackTrace();
            return false;
        }
        finally {
            DBUtils.closeConnection();
        }
    }

    public boolean add(User user)
    {
        Connection connection = DBUtils.getConnection();
        String sql = "insert into user(name,password) values(?,?)";
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,user.getName());
            preparedStatement.setString(2,user.getPassword());
            preparedStatement.executeUpdate();
            return preparedStatement.getUpdateCount() != 0;
        }
        catch (SQLException e)
        {
            e.printStackTrace();
            return false;
        }
        finally {
            DBUtils.closeConnection();
        }
    }
}

В основном это операции запроса и добавления. Если пользователь существует в операции запроса, он будет возвращен.true, иначе возвратfalse.

использовать в операции добавленияexecuteUpdate()а такжеgetUpdateCount() != 0.

Обратите внимание, что его нельзя использовать напрямую

return preparedStatement.execute();

заменить

preparedStatement.executeUpdate();
return preparedStatement.getUpdateCount() != 0;

На первый взгляд вроде бы и нет проблем.Когда автор тестировал той ночью, проблема была большая.AndroidОн показывает, что регистрация не удалась, но база данных неinsertпошел в. . .

Ах это. . .

Ну, это все еще функциональная проблема.

  • Вообще говоряselectиспользоватьexecuteQuery(),executeQuery()вернутьResultSet, представляющий набор результатов, сохраненныйselectРезультат выполнения инструкции, сnext()использовать
  • delete,insert,updateиспользоватьexecuteUpdate(),executeUpdate()Возвращается целое число, представляющее количество затронутых строк, т.е.delete,insert,updateколичество измененных строк, дляdrop,createОперация возвращается0
  • create,dropиспользоватьexecute(),execute()Возвращаемое значение похоже на это, если первый результатResultSetобъект, возвратtrue, вернуть, если первым результатом является количество обновлений или если результата нетfalse

Итак, в этом примере

return preparedStatement.execute();

обязательно вернусьfalse, так что это будет сторона базы данныхinsertЗахожу, но интерфейс показывает, что регистрация не удалась (давно искал эту проблему...)

5.7 SignIn+SignUp

servletв сумке:

  • SingInкласс для обработки входа, вызоваJDBCПроверить, есть ли соответствующий пользователь в базе данных
  • SignUpкласс для обработки регистрации, положитьUserдобавить в базу данных

SignIn.javaследующим образом:

@WebServlet("/SignIn")
public class SingIn extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException,ServletException
    {
        this.doPost(httpServletRequest,httpServletResponse);
    }

    @Override
    protected void doPost(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws IOException, ServletException
    {
        httpServletRequest.setCharacterEncoding("utf-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("text/plain;charset=utf-8");//设置相应类型为html,编码为utf-8

        String name = httpServletRequest.getParameter("name");
        String password = httpServletRequest.getParameter("password");

        UserDao userDao = new UserDao();
        User user = new User();
        user.setName(name);
        user.setPassword(password);

        if(!userDao.query(user))//若查询失败
        {
            httpServletResponse.sendError(204,"query failed.");//设置204错误码与出错信息
        }
    }
}

прежде всего@WebServletАннотация, указывающая, что это имя называетсяSignInизServlet, который можно использовать для реализацииServletа такжеURLсопоставление, если вы не добавите сюда эту аннотацию, вам нужноWEB-INFв каталогеweb.xmlдобавить один<servlet-mapping>.

@WebServlet("/SignIn")

Затем установите тип ответа и кодировку:

httpServletResponse.setContentType("text/plain;charset=utf-8");//设置相应类型为html,编码为utf-8

HttpServletRequest.getParameter(String name)метод согласноnameПолучите соответствующие параметры:

String name = httpServletRequest.getParameter("name");
String password = httpServletRequest.getParameter("password");

НижеSignUp.java:

@WebServlet("/SignUp")
public class SignUp extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws IOException,ServletException
    {
        this.doPost(httpServletRequest,httpServletResponse);
    }

    @Override
    protected void doPost(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws IOException,ServletException
    {
        httpServletRequest.setCharacterEncoding("utf-8");
        httpServletResponse.setCharacterEncoding("utf-8");//设定编码防止中文乱码
        httpServletResponse.setContentType("text/plain;charset=utf-8");//设置相应类型为html,编码为utf-8

        String name = httpServletRequest.getParameter("name");//根据name获取参数
        String password = httpServletRequest.getParameter("password");//根据password获取参数

        UserDao userDao = new UserDao();
        User user = new User();
        user.setName(name);
        user.setPassword(password);

        if(!userDao.add(user)) //若添加失败
        {
            httpServletResponse.sendError(204,"add failed.");//设置204错误码与出错信息
        }
    }
}

5.8 ДобавитьServletприбытьweb.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>SignIn</servlet-name>
        <servlet-class>com.servlet.SingIn</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>SignUp</servlet-name>
        <servlet-class>com.servlet.SignUp</servlet-class>
    </servlet>
</web-app>

Поместить только что созданныйServletдобавить вweb.xml,существует<servlet>добавить дочерний элемент<servlet-name>а также<servlet-class>:

  • <servlet-name>даServletИмя рекомендуется согласовывать с именем класса
  • <servlet-class>даServletрасположение класса

если вServletкласс не добавлен@WebServlet("/xxxx")аннотация, вам нужноweb.xmlдобавлять:

<servlet-mapping>
	<servlet-name>SignIn</servlet-name>
	<url-pattern>/SignIn</url-pattern>
</servlet-mapping>

в<servlet-name>а также<servlet>дочерние элементы в<servlet-name>Значения в одинаковые,<url-pattern>это путь доступа.

5.9 Hello.htmlтестовый файл

Наконец добавьтеHello.htmlтестовый файл.

<!DOCTYPE html>
    <head>
        <meta charset="utf-8">
        <title>Welcome</title>
    </head>
    <body>
        Hello web.
    </body>
</html>

6 Пакетный выпуск

Автор использовалIDEA,Упаковку Eclipse смотрите здесь.

6.1 Project Structure->Artifacts->Web Application:Archive

在这里插入图片描述

在这里插入图片描述

6.2 Создайте каталог и добавьте модули

изменить имя и создатьWEB-INFКаталоги и подкаталогиclasses:

在这里插入图片描述

проверилclasses,Добавить кModule Output, выберите собственный веб-проект:

在这里插入图片描述

6.3 Добавление зависимых библиотек и других файлов

Добавить кJARпакет, провереноlibДобавьте файл пакета JAR после каталога:

在这里插入图片描述

Затем добавьтеHello.htmlа такжеweb.xml,web.xmlнуждаться вWEB-INFкаталог,Hello.htmlсуществуетWEB-INFЗа пределами:

在这里插入图片描述

6.4 Упаковка

Build->Build Artifacts:在这里插入图片描述

在这里插入图片描述

6.5 Тест загрузки

упакованныйWARзагрузка файла на серверTomcatизwebappsПод содержанием:

scp ***.war username@xxx.xxx.xxx.xxx:/usr/local/tomcat/webapps

Будьте осторожны, чтобы изменить его на свой собственныйwebappsсодержание.

TomcatПосле запуска введите в браузере

服务器IP:端口/项目/Hello.html

Я протестировал его локально для удобства:

在这里插入图片描述

7 Androidконец

7.1 Новое строительство

在这里插入图片描述

在这里插入图片描述

7.2 MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button signin = (Button) findViewById(R.id.signin);
        signin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String name = ((EditText) findViewById(R.id.etname)).getText().toString();
                String password = ((EditText) findViewById(R.id.etpassword)).getText().toString();
                if (UserService.signIn(name, password))
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                        }
                    });
                else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        });


        Button signup = (Button) findViewById(R.id.signup);
        signup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String name = ((EditText) findViewById(R.id.etname)).getText().toString();
                String password = ((EditText) findViewById(R.id.etpassword)).getText().toString();
                if (UserService.signUp(name, password))
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "注册成功", Toast.LENGTH_SHORT).show();
                        }
                    });
                else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "注册失败", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        });
    }
}

два простыхButtonПривяжите событие, затем установите дваToastоперативная информация.

7.3 UserService.java

public class UserService {
    public static boolean signIn(String name, String password) {
        MyThread myThread = new MyThread("http://本机内网IP:8080/cx/SignIn",name,password);
        try
        {
            myThread.start();
            myThread.join();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        return myThread.getResult();
    }

    public static boolean signUp(String name, String password) {
        MyThread myThread = new MyThread("http://本机内网IP:8080/cx/SignUp",name,password);
        try
        {
            myThread.start();
            myThread.join();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        return myThread.getResult();
    }
}

class MyThread extends Thread
{
    private String path;
    private String name;
    private String password;
    private boolean result = false;

    public MyThread(String path,String name,String password)
    {
        this.path = path;
        this.name = name;
        this.password = password;
    }
    @Override
    public void run()
    {
        try {
            URL url = new URL(path);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setConnectTimeout(8000);//设置连接超时时间
            httpURLConnection.setReadTimeout(8000);//设置读取超时时间
            httpURLConnection.setRequestMethod("POST");//设置请求方法,post

            String data = "name=" + URLEncoder.encode(name, "utf-8") + "&password=" + URLEncoder.encode(password, "utf-8");//设置数据
            httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//设置响应类型
            httpURLConnection.setRequestProperty("Content-Length", data.length() + "");//设置内容长度
            httpURLConnection.setDoOutput(true);//允许输出
            OutputStream outputStream = httpURLConnection.getOutputStream();
            outputStream.write(data.getBytes("utf-8"));//写入数据
            result = (httpURLConnection.getResponseCode() == 200);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean getResult()
    {
        return result;
    }
}
MyThread myThread = new MyThread("http://内网IP:8080/cx/SignUp",name,password);
MyThread myThread = new MyThread("http://内网IP:8080/cx/SignIn",name,password);

Замените эти две строки своимиip, интранетipможет быть использованipconfigилиifconfigПроверьте, если порт по умолчанию изменен, порт также изменен.

Путь:

端口/web项目名/Servlet名

webНазвание проекта перепечатаноWARустанавливается во время упаковки,Servletимя вweb.xmlсередина<servlet>дочерний элемент<servlet-name>настройки, а в исходном коде@WebServlet()Аннотации те же.

Еще одна вещь, на которую следует обратить внимание, это проблема с потоком, вам нужно открыть новый поток дляHTTPСвязь.

7.4 activity_main.xml

Интерфейсная часть страницы очень проста, всего две кнопки для функции проверки.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical"
    >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="用户名"
            />
        <EditText
            android:layout_width="300dp"
            android:layout_height="60dp"
            android:id="@+id/etname"
            />
    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码"
            />
        <EditText
            android:layout_width="300dp"
            android:layout_height="60dp"
            android:id="@+id/etpassword"
            />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:layout_width="120dp"
            android:layout_height="60dp"
            android:text="注册"
            android:id="@+id/signup"
            />
        <Button
            android:layout_width="120dp"
            android:layout_height="60dp"
            android:text="登录"
            android:id="@+id/signin"
            />
    </LinearLayout>
</LinearLayout>

8 тест

8.1 Регистрационный тест

Просто введите имя пользователя и пароль:

在这里插入图片描述

Посмотреть базу данных:

在这里插入图片描述

8.2 Проверка входа

在这里插入图片描述

9 Примечания

9.1 Имя пользователя и пароль базы данных

Имя пользователя и пароль базы данных должны быть установлены правильно, иначе будет выдано исключение, как показано ниже:

在这里插入图片描述

Эта ошибка также может возникать при загрузке ошибки драйвера, поэтому обязательно введитеWARвремя пакетаlibкаталог правильный иJARВерсия пакета правильная.

Кроме того, поскольку этоJDBCОсновная реализация, обратите внимание на рукописныйSQLУтверждения не могут быть ошибочными.

Не будь как автор:

在这里插入图片描述

9.2 Проблемы с сетевыми разрешениями

нуждаться вAndroidManifest.xmlДобавьте сетевые разрешения:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

9.3 Проблемы с группой безопасности/брандмауэром

Поскольку, если текущий облачный сервер обычно использует группы безопасности вместо непосредственного использования брандмауэра для настройки параметров безопасности, если вы не можете получить доступ, откройте порт в соответствующей конфигурации группы безопасности на облачном сервере.8080порт, вообще разрешить всеipчерез, источникipнастроен как0.0.0.0/0,Например:

在这里插入图片描述

Если группа безопасности установлена ​​и доступ пройден, возможно проблема с брандмауэром сервера, можете проверить.iptables(CentOS8использоватьfirewalld) включен:

systemctl status iptables

Если он включен, вы можете отключить его:

systemctl stop iptables

Если он не закрыт, вы можете добавить правила порта и изменить/etc/sysconfig/iptables:

vim /etc/sysconfig/iptables

Добавить к

-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT

перезагружатьiptables:

systemctl restart iptables

9.4 HTTPМеры предосторожности

из-за отAndroid PStart, по умолчанию требует использования зашифрованных соединений, то есть использоватьHTTPS, поэтому использованиеHTTPсоединять.

использоватьHTTPПри подключении возникает следующее исключение:

W/System.err: java.io.IOException: Cleartext HTTP traffic to **** not permitted
java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy

Два решения:

  • использоватьHTTPS
  • изменить значение по умолчаниюAndroidManifest.xmlсделай это позволеннымHTTPсоединять

существуетresсоздать новую папкуxml, создатьnetwork_security_config.xmlфайл, содержание файла следующее

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

затем вAndroidMainfest.xmlДобавить в:

<application
 android:networkSecurityConfig="@xml/network_security_config"
/>

Вот и все.

Если вышеуказанный метод не работает, вы можете попробовать его непосредственно вAndroidManifest.xmlПросто добавьте фразу:

<application 
android:usesCleartextTraffic="true"
/>

9.5 Проблемы с потоками

отAndroid 4.0Вначале сеть не может работать в основном потоке.Если сеть не в порядке, она зависнет.Поэтому все операции, связанные с сетью, должны открывать новый поток и не могут работать в основном потоке.

9.6 AVDвопрос

在这里插入图片描述

Я долго искал этот вопрос,HTTPНет проблем с подключением, нет проблем с сервером, нет проблем с базой данных, нет проблем с интерфейсным кодом, и впередStackOverflow, найдено, чтоAVDПроблема. . .

在这里插入图片描述

Просто удалите егоAPPперезагрузиться сноваAVD, на самом деле удалось. . .

9.8 404

По комментариям (спасибо всем, кто тут комментировал) появится404Была проблема404Основная причина в том, что путь доступа неверный. Вот три случая, которые нужно объяснить.

9.8.1 МестныйIDEAдоступ в

IDEAПосле запуска проекта вы можете использоватьpostmanДля проверки перейдите по пути:

http://localhost:8080/SignIn

То есть, поскольку в настоящее время он не упакован, поэтому нет необходимости добавлять имя упакованного проекта.

9.8.2 МестныйTomcatдоступ

После упаковки будетxxx.warпакетный файл, например, называемыйdemo.war, затем используйтеpostmanТестовый путь станет

http://localhost:8080/demo/SignIn

потому чтоTomcatбудет автоматическиdemo.warраспаковать, запуститьTomcatпозжеwebappsДалее будет звонокdemoпапка, которая содержит упакованные файлы, путь в это время должен начинаться сdemoв качестве эталона, такSignInнужно добавить передdemo.

9.8.3 Развернуто на сервереTomcat

После развертывания на сервере с локальнымTomcatв основном то же самое, просто поместите соответствующийlocahostИзменение на соответствующее доменное имя или общедоступную сетьipВы можете, например:

http://www.example.com:8080/demo/SignIn
http://111.111.111.111:8080/demo/SignIn

10 исходный код иJARСумка

10.1 JARСумка

Другие версии могут прийтиздесьНайдите и скачайте.

10.2 Исходный код

11 Последний

Прежде всего, я хотел бы поблагодарить читателей за то, что они смогли прочитать конец. Автор действительно потратил много времени на написание этой статьи. Тем не менее, всегда будет что-то не так или непонятно для читателей. Надеюсь, у читателей есть какие-либо вопросы или другие вопросы.Их можно написать в приват автору или указать в комментариях. ,Благодарен.

12 справочных сайтов

1,CSDN-Android взаимодействует с базой данных Mysql через веб-сервер.

2,Не удалось подключиться к сети CSDN-Android высокой версии

3.CSDN-IDEA развертывает веб-проекты

4.executeQuery, executeUpdate и выполнение CSDN-PreparedStatement

5.Операция execute() CSDN-preparedstatement выполнена успешно! но возвращает ложь

6.CSDN-HttpServletResponse (1)

7.CSDN-HttpServletResponse (2)

8,CSDN-HttpServletRequest

9,StackOverflow-HttpUrlConnection

10.StackOverflow-java.net.socketexception

Если вы считаете, что статья хорошая, ставьте лайк.

В то же время приглашаем обратить внимание на публичный аккаунт WeChat: Bingling Road.