2021.1.27 更新

已更新新版本博客,更新内容与原文章相比有点多,因此新开了一篇博客,请戳这里

1 背景

开发一个App与后台数据库交互,基于MySQL+原生JDBC+Tomcat,没有使用DBUtilsJDBC框架,纯粹底层JDBC实现。

这几天踩了很多坑,说得夸张点真是踩到没有知觉,希望能帮助读者少踩坑...

2 开发环境

  • Windows10
  • 服务器CentOS 7
  • Android Studio 3.5.1
  • IntelliJ IDEA 2019.02
  • MySQL 8.0.17
  • Tomcat 9.0.26

3 准备环境

主要是安装MySQLTomcat,已经安装的可以略过。

3.1 安装MySQL

这个是目前比较新的MySQL版本。

服务器系统是CentOS

其他系统安装看这里:

CentOS使用yum安装即可。

3.1.1 下载并安装MySQL

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

3.1.2 启动服务并查看初始化密码

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

3.1.3 修改密码

首先使用root登录:

  1. mysql -u root -p

输入上一步看到的密码,接着使用alter修改密码:

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

注意新版本的MySQL不能使用太弱的密码,比如:



出现这种提示的话则说明密码太弱了,请使用一个更高强度的密码。

3.1.4 允许外部访问

  1. use mysql;
  2. 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命令,使用不熟练的可以戳这里看看

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

改成自己的用户名和ip

3.2.2 解压

ssh连接到服务器,接着移动到/usr/local并解压:

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

3.2.3 修改默认端口(可选)

修改conf/server.xml文件,一般只需修改

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

中的8080端口,修改这个端口即可。

需要的话自行更改。

3.2.4 启动

运行bin目录下的startup.sh:

  1. cd bin
  2. ./startup.sh

3.2.5 测试

浏览器输入:

  1. 服务器IP:端口

若出现:

则表示成功。

3.2.6 开机启动(可选)

建议配置开机启动,修改/etc/rc.local文件,添加:

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

这个根据自己的Tomcat安装路径修改,指定bin下的startup.sh

4 建库建表

创建用户表,这里简化操作就不创建新用户不授权了。

这是一个在本地用root登录的示例,请根据实际情况创建并授权用户。

4.1 用户表

  1. CREATE DATABASE userinfo;
  2. USE userinfo;
  3. CREATE TABLE user
  4. (
  5. id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  6. name CHAR(30) NULL,
  7. password CHAR(30) NULL
  8. );

4.2 导入

  1. 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.javaSignIn.java
  • com.util:主要功能是数据库连接,包含DBUtils.java
  • com.entity:实体类,包含User.java
  • com.dao:操作用户类的类,包含UserDao.java

5.4 DBUtils

连接数据库的类,纯粹的底层JDBC实现,注意驱动版本

  1. public class DBUtils {
  2. private static Connection connection = null;
  3. public static Connection getConnection()
  4. {
  5. try {
  6. Class.forName("com.mysql.cj.jdbc.Driver");
  7. String url = "jdbc:mysql://127.0.0.1:3306/数据库名字";
  8. String usename = "账号";
  9. String password = "密码";
  10. connection = DriverManager.getConnection(url,usename,password);
  11. }
  12. catch (Exception e)
  13. {
  14. e.printStackTrace();
  15. return null;
  16. }
  17. return connection;
  18. }
  19. public static void closeConnection()
  20. {
  21. if(connection != null)
  22. {
  23. try {
  24. connection.close();
  25. }
  26. catch (SQLException e)
  27. {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
  32. }

主要就是获取连接与关闭连接两个函数。

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

这几行根据自己的用户名,密码,服务器ip和库名修改。

注意,MySQL 8.0以上使用的注册驱动的语句是:

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

旧版的是:

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

5.5 User

User类比较简单,就是就三个字段与Getter+Setter

  1. public class User {
  2. private int id;
  3. private String name;
  4. private String password;
  5. //三个Getter与三个Setter
  6. //...
  7. }

5.6 UserDao

  1. public class UserDao {
  2. public boolean query(User user)
  3. {
  4. Connection connection = DBUtils.getConnection();
  5. String sql = "select * from user where name = ? and password = ?";
  6. try {
  7. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  8. preparedStatement.setString(1,user.getName());
  9. preparedStatement.setString(2,user.getPassword());
  10. ResultSet resultSet = preparedStatement.executeQuery();
  11. return resultSet.next();
  12. }
  13. catch (SQLException e)
  14. {
  15. e.printStackTrace();
  16. return false;
  17. }
  18. finally {
  19. DBUtils.closeConnection();
  20. }
  21. }
  22. public boolean add(User user)
  23. {
  24. Connection connection = DBUtils.getConnection();
  25. String sql = "insert into user(name,password) values(?,?)";
  26. try {
  27. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  28. preparedStatement.setString(1,user.getName());
  29. preparedStatement.setString(2,user.getPassword());
  30. preparedStatement.executeUpdate();
  31. return preparedStatement.getUpdateCount() != 0;
  32. }
  33. catch (SQLException e)
  34. {
  35. e.printStackTrace();
  36. return false;
  37. }
  38. finally {
  39. DBUtils.closeConnection();
  40. }
  41. }
  42. }

主要就是查询与添加操作,查询操作中存在该用户就返回true,否则返回false

添加操作中使用executeUpdate()getUpdateCount() != 0

注意不能直接使用

  1. return preparedStatement.execute();

去代替

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

咋一看好像没有什么问题,那天晚上笔者测试的时候问题可大了,Android那边显示注册失败,但是数据库这边的却insert进去了。。。

啊这。。。

好吧,还是函数的问题。

  • 一般来说select使用executeQuery(),executeQuery()返回ResultSet,表示结果集,保存了select语句的执行结果,配合next()使用
  • delete,insert,update使用executeUpdate(),executeUpdate()返回的是一个整数,表示受影响的行数,即delete,insert,update修改的行数,对于dropcreate操作返回0
  • createdrop使用execute(),execute()的返回值是这样的,如果第一个结果是ResultSet对象,则返回true,如果第一个结果是更新计数或者没有结果则返回false

所以在这个例子中

  1. return preparedStatement.execute();

肯定返回false,所以才会数据库这边insert进去,但前端显示注册失败(这个问题笔者找了是真的久。。。)

5.7 SignIn+SignUp

servlet包中:

  • SingIn类用于处理登录,调用JDBC查看数据库是否有对应的用户
  • SignUp类用于处理注册,把User添加到数据库中

SignIn.java如下:

  1. @WebServlet("/SignIn")
  2. public class SingIn extends HttpServlet {
  3. @Override
  4. protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException,ServletException
  5. {
  6. this.doPost(httpServletRequest,httpServletResponse);
  7. }
  8. @Override
  9. protected void doPost(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws IOException, ServletException
  10. {
  11. httpServletRequest.setCharacterEncoding("utf-8");
  12. httpServletResponse.setCharacterEncoding("utf-8");
  13. httpServletResponse.setContentType("text/plain;charset=utf-8");//设置相应类型为html,编码为utf-8
  14. String name = httpServletRequest.getParameter("name");
  15. String password = httpServletRequest.getParameter("password");
  16. UserDao userDao = new UserDao();
  17. User user = new User();
  18. user.setName(name);
  19. user.setPassword(password);
  20. if(!userDao.query(user))//若查询失败
  21. {
  22. httpServletResponse.sendError(204,"query failed.");//设置204错误码与出错信息
  23. }
  24. }
  25. }

首先是@WebServlet注解,表示这是一个名字叫SignInServlet,可用于实现ServletURL的映射,如果不在这里添加这个注解,则需要在WEB-INF目录下的web.xml添加一个<servlet-mapping>

  1. @WebServlet("/SignIn")

接着设置响应类型与编码:

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

HttpServletRequest.getParameter(String name)方法表示根据name获取相应的参数:

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

下面是SignUp.java

  1. @WebServlet("/SignUp")
  2. public class SignUp extends HttpServlet {
  3. @Override
  4. protected void doGet(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws IOException,ServletException
  5. {
  6. this.doPost(httpServletRequest,httpServletResponse);
  7. }
  8. @Override
  9. protected void doPost(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws IOException,ServletException
  10. {
  11. httpServletRequest.setCharacterEncoding("utf-8");
  12. httpServletResponse.setCharacterEncoding("utf-8");//设定编码防止中文乱码
  13. httpServletResponse.setContentType("text/plain;charset=utf-8");//设置相应类型为html,编码为utf-8
  14. String name = httpServletRequest.getParameter("name");//根据name获取参数
  15. String password = httpServletRequest.getParameter("password");//根据password获取参数
  16. UserDao userDao = new UserDao();
  17. User user = new User();
  18. user.setName(name);
  19. user.setPassword(password);
  20. if(!userDao.add(user)) //若添加失败
  21. {
  22. httpServletResponse.sendError(204,"add failed.");//设置204错误码与出错信息
  23. }
  24. }
  25. }

5.8 添加Servletweb.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5. version="4.0">
  6. <servlet>
  7. <servlet-name>SignIn</servlet-name>
  8. <servlet-class>com.servlet.SingIn</servlet-class>
  9. </servlet>
  10. <servlet>
  11. <servlet-name>SignUp</servlet-name>
  12. <servlet-class>com.servlet.SignUp</servlet-class>
  13. </servlet>
  14. </web-app>

要把刚才创建的Servlet添加进web.xml,在<servlet>中添加子元素<servlet-name><servlet-class>

  • <servlet-name>Servlet的名字,建议与类名一致
  • <servlet-class>Servlet类的位置

如果在Servlet类中没有添加@WebServlet("/xxxx")注解,则需要在web.xml中添加:

  1. <servlet-mapping>
  2. <servlet-name>SignIn</servlet-name>
  3. <url-pattern>/SignIn</url-pattern>
  4. </servlet-mapping>

其中<servlet-name><servlet>中的子元素<servlet-name>中的值一致,<url-pattern>是访问的路径。

5.9 Hello.html测试文件

最后添加一个叫Hello.html的测试文件。

  1. <!DOCTYPE html>
  2. <head>
  3. <meta charset="utf-8">
  4. <title>Welcome</title>
  5. </head>
  6. <body>
  7. Hello web.
  8. </body>
  9. </html>

6 打包发布

笔者用的IDEAEclipse的打包请看这里

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

6.2 创建目录并添加模块

修改名字,并创建WEB-INF目录与子目录classes

选中classes,添加Module Output,选择自己的web项目:

6.3 添加依赖库与其他文件

添加JAR包,选中lib目录后添加JAR包文件:

接着添加Hello.htmlweb.xmlweb.xml需要在WEB-INF目录里,Hello.htmlWEB-INF外面:

6.4 打包

Build->Build Artifacts

6.5 上传测试

打包好的WAR文件上传到服务器Tomcatwebapps目录下:

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

注意改成自己的webapps目录。

Tomcat启动后,在浏览器输入

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

笔者为了方便就在本地测试了:

7 Android

7.1 新建工程

7.2 MainActivity.java

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. Button signin = (Button) findViewById(R.id.signin);
  7. signin.setOnClickListener(new View.OnClickListener() {
  8. @Override
  9. public void onClick(View view) {
  10. String name = ((EditText) findViewById(R.id.etname)).getText().toString();
  11. String password = ((EditText) findViewById(R.id.etpassword)).getText().toString();
  12. if (UserService.signIn(name, password))
  13. runOnUiThread(new Runnable() {
  14. @Override
  15. public void run() {
  16. Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
  17. }
  18. });
  19. else {
  20. runOnUiThread(new Runnable() {
  21. @Override
  22. public void run() {
  23. Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
  24. }
  25. });
  26. }
  27. }
  28. });
  29. Button signup = (Button) findViewById(R.id.signup);
  30. signup.setOnClickListener(new View.OnClickListener() {
  31. @Override
  32. public void onClick(View view) {
  33. String name = ((EditText) findViewById(R.id.etname)).getText().toString();
  34. String password = ((EditText) findViewById(R.id.etpassword)).getText().toString();
  35. if (UserService.signUp(name, password))
  36. runOnUiThread(new Runnable() {
  37. @Override
  38. public void run() {
  39. Toast.makeText(MainActivity.this, "注册成功", Toast.LENGTH_SHORT).show();
  40. }
  41. });
  42. else {
  43. runOnUiThread(new Runnable() {
  44. @Override
  45. public void run() {
  46. Toast.makeText(MainActivity.this, "注册失败", Toast.LENGTH_SHORT).show();
  47. }
  48. });
  49. }
  50. }
  51. });
  52. }
  53. }

两个简单的Button绑定事件,然后设置两个Toast提示信息。

7.3 UserService.java

  1. public class UserService {
  2. public static boolean signIn(String name, String password) {
  3. MyThread myThread = new MyThread("http://本机内网IP:8080/cx/SignIn",name,password);
  4. try
  5. {
  6. myThread.start();
  7. myThread.join();
  8. }
  9. catch (InterruptedException e)
  10. {
  11. e.printStackTrace();
  12. }
  13. return myThread.getResult();
  14. }
  15. public static boolean signUp(String name, String password) {
  16. MyThread myThread = new MyThread("http://本机内网IP:8080/cx/SignUp",name,password);
  17. try
  18. {
  19. myThread.start();
  20. myThread.join();
  21. }
  22. catch (InterruptedException e)
  23. {
  24. e.printStackTrace();
  25. }
  26. return myThread.getResult();
  27. }
  28. }
  29. class MyThread extends Thread
  30. {
  31. private String path;
  32. private String name;
  33. private String password;
  34. private boolean result = false;
  35. public MyThread(String path,String name,String password)
  36. {
  37. this.path = path;
  38. this.name = name;
  39. this.password = password;
  40. }
  41. @Override
  42. public void run()
  43. {
  44. try {
  45. URL url = new URL(path);
  46. HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
  47. httpURLConnection.setConnectTimeout(8000);//设置连接超时时间
  48. httpURLConnection.setReadTimeout(8000);//设置读取超时时间
  49. httpURLConnection.setRequestMethod("POST");//设置请求方法,post
  50. String data = "name=" + URLEncoder.encode(name, "utf-8") + "&password=" + URLEncoder.encode(password, "utf-8");//设置数据
  51. httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//设置响应类型
  52. httpURLConnection.setRequestProperty("Content-Length", data.length() + "");//设置内容长度
  53. httpURLConnection.setDoOutput(true);//允许输出
  54. OutputStream outputStream = httpURLConnection.getOutputStream();
  55. outputStream.write(data.getBytes("utf-8"));//写入数据
  56. result = (httpURLConnection.getResponseCode() == 200);
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. public boolean getResult()
  62. {
  63. return result;
  64. }
  65. }
  1. MyThread myThread = new MyThread("http://内网IP:8080/cx/SignUp",name,password);
  2. MyThread myThread = new MyThread("http://内网IP:8080/cx/SignIn",name,password);

这两行换成自己的ip,内网ip的话可以用ipconfigifconfig查看,修改了默认端口的话也把端口一起改了。

路径的话就是:

  1. 端口/web项目名/Servlet

web项目名是再打成WAR包时设置的,Servlet名在web.xml中的<servlet>的子元素<servlet-name>设置,与源码中的@WebServlet()注解一致。

另外一个要注意的就是线程问题,需要新开一个线程进行HTTP的连接。

7.4 activity_main.xml

前端页面部分很简单,就两个按钮,用于验证功能。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:android="http://schemas.android.com/apk/res/android"
  5. android:layout_height="match_parent"
  6. android:layout_width="match_parent"
  7. android:orientation="vertical"
  8. >
  9. <LinearLayout
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:orientation="horizontal">
  13. <TextView
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. android:text="用户名"
  17. />
  18. <EditText
  19. android:layout_width="300dp"
  20. android:layout_height="60dp"
  21. android:id="@+id/etname"
  22. />
  23. </LinearLayout>
  24. <LinearLayout
  25. android:layout_width="wrap_content"
  26. android:layout_height="wrap_content"
  27. android:orientation="horizontal">
  28. <TextView
  29. android:layout_width="wrap_content"
  30. android:layout_height="wrap_content"
  31. android:text="密码"
  32. />
  33. <EditText
  34. android:layout_width="300dp"
  35. android:layout_height="60dp"
  36. android:id="@+id/etpassword"
  37. />
  38. </LinearLayout>
  39. <LinearLayout
  40. android:layout_width="wrap_content"
  41. android:layout_height="wrap_content"
  42. android:orientation="horizontal">
  43. <Button
  44. android:layout_width="120dp"
  45. android:layout_height="60dp"
  46. android:text="注册"
  47. android:id="@+id/signup"
  48. />
  49. <Button
  50. android:layout_width="120dp"
  51. android:layout_height="60dp"
  52. android:text="登录"
  53. android:id="@+id/signin"
  54. />
  55. </LinearLayout>
  56. </LinearLayout>

8 测试

8.1 注册测试

随便输入用户名与密码:

查看数据库:

8.2 登录测试

9 注意事项

9.1 数据库用户名与密码

数据库的用户名和密码一定要设置正确,要不然会像下图一样抛出异常:

在加载驱动错误时也可能会出现这个错误,因此要确保打成WAR包时lib目录正确且JAR包版本正确。

还有就是由于这个是JDBC的底层实现,注意手写的SQL语句不能错。

千万千万别像笔者这样:

9.2 网络权限问题

需要在AndroidManifest.xml添加网络权限:

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

9.3 安全组/防火墙问题

因为如果是现在的云服务器一般都使用安全组而不是直接使用防火墙配置安全设置,所以如果没法访问请到云服务器上面对应的安全组配置中开放端口,默认是8080端口,一般是允许所有ip通过,源ip配置为0.0.0.0/0,比如:

如果设置了安全组通过了,还是不能访问,可能是服务器防火墙的问题,可以查看iptablesCentOS8使用firewalld)是否开启:

  1. systemctl status iptables

开启的话可以选择关闭:

  1. systemctl stop iptables

若不关闭,可以添加端口规则,修改/etc/sysconfig/iptables

  1. vim /etc/sysconfig/iptables

添加

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

重启iptables

  1. systemctl restart iptables

9.4 HTTP注意事项

由于从Android P开始,默认要求使用加密连接,也就是要使用HTTPS,所以会禁止使用HTTP连接。

使用HTTP连接时会出现以下异常:

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

两种解决办法:

  • 使用HTTPS
  • 修改默认的AndroidManifest.xml使其允许HTTP连接

res下新建一个文件夹xml,创建一个叫network_security_config.xml的文件,文件内容如下

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <network-security-config>
  3. <base-config cleartextTrafficPermitted="true" />
  4. </network-security-config>

然后在AndroidMainfest.xml中加入:

  1. <application
  2. android:networkSecurityConfig="@xml/network_security_config"
  3. />

即可。

如果上面的方法不行,可以试一下直接在AndroidManifest.xml直接加入一句:

  1. <application
  2. android:usesCleartextTraffic="true"
  3. />

9.5 线程问题

Android 4.0开始,联网不能在主线程操作,万一网络不好就会卡死,所以有关联网的操作都需要新开一个线程,不能在主线程操作。

9.6 AVD问题

这个问题笔者找了很久,HTTP连接没问题,服务器没问题,数据库没问题,前端代码没问题,然后去了StackOverflow,发现是AVD的问题。。。

简单来说就是卸载了APP再重启AVD,居然成功了。。。

9.8 404

根据评论反映(这里同时感谢评论的各位)会出现404问题,出现404的主要原因就是访问路径的不正确,这里分三种情况进行说明。

9.8.1 本地IDEA中访问

IDEA运行项目后,可以使用postman进行测试,访问路径:

  1. http://localhost:8080/SignIn

即可,因为此时还没有打包,所以不需要加上打包的项目名。

9.8.2 本地Tomcat访问

打包后会有一个叫xxx.war的打包文件,比如叫demo.war,那么使用postman测试的路径就要变为

  1. http://localhost:8080/demo/SignIn

因为Tomcat会自动把demo.war解包,运行Tomcat后会在webapps下会有一个叫demo的文件夹,里面就是打包后的文件,此时的路径需要以demo为基准,因此SignIn前需要加上demo

9.8.3 部署到服务器的Tomcat

部署到服务器后与本地Tomcat是基本一样的,只是把对应的locahost改成对应的域名或者公网ip即可,比如:

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

10 源码与JAR

10.1 JAR

其他版本可以来这里搜索下载.

10.2 源码

11 最后

首先感谢读者能看到末尾,笔者也确实花了不少时间写这篇文章,但是,总会有不对或让读者疑惑的地方,希望读者有疑问或者其他什么问题可以私信笔者或在评论中指出,感激不尽。

12 参考网站

1、CSDN-Android 通过Web服务器与Mysql数据库交互

2、CSDN-Android高版本联网失败

3、CSDN-IDEA 部署Web项目

4、CSDN-PreparedStatement的executeQuery、executeUpdate和execute

5、CSDN-preparedstatement execute()操作成功!但是返回false

6、CSDN-HttpServletResponse(一)

7、CSDN-HttpServletResponse(二)

8、CSDN-HttpServletRequest

9、StackOverflow-HttpUrlConnection

10、StackOverflow-java.net.socketexception

如果觉得文章好看,欢迎点赞。

同时欢迎关注微信公众号:氷泠之路。

Android通过Web与后台数据库交互的更多相关文章

  1. python web开发——c3 数据库交互和flask-SQLALchemy

    ORM(对象关系映射) 定义:将数据库中表与表之间的关系和代码中类(class)与类之间的关系联系起来,这就是ORM

  2. 利用ajax的方式来提交数据到后台数据库及交互功能

    怎么样用ajax来提交数据到后台数据库,并完成交互呢????? 一.当我们在验证表单的时候,为了阻止把错误的也发送到服务器,我们通常这样设置:     $(function(){       var ...

  3. Java后台+数据库+Java web前端(新手)

    实现简单页面上对数据的增删改查:Java后台+数据库表+Jsp前端网页设计 这里做一个简单的学生课程信息管理系统,做之前一定要先有自己的思路,要不然对新手来说,很容易乱的. 另有一完整的代码可供参考, ...

  4. python中web应用与mysql数据库交互

    7使用数据库 具体使用python的DB-API,这一章里介绍如何编写代码与MYSQL数据库技术交互,这里使用一个通用的数据库API,名为DB-API. 7.1基于数据库的web应用 之前我们把日志数 ...

  5. Android+Java Web+MySQL实现登录注册

    1 前言&概述 这篇文章是基于此处文章的更新,更新了一些技术栈,更加贴近实际需要,以及修复了若干的错误. 这是一个前端Android+后端Java/Kotlin通过Servelt进行后台数据库 ...

  6. 我的Android 4 学习系列之数据库和Content Provider

    目录 创建数据库和使用SQLite 使用Content Provider.Cusor和Content Value来存储.共享和使用应用程序数据 使用Cursor Loader异步查询Content P ...

  7. asp.net中javascript与后台c#交互

    asp.net中javascript与后台c#交互 作者:熊猫大叔 字体:[增加 减小] 类型:转载 时间:2015-10-23我要评论,出处:http://www.jb51.net/article/ ...

  8. .NET应用程序与数据库交互的若干问题

    我们知道,在应用程序中与数据库进行交互是一个比较耗时的过程,首先应用程序需要与应用程序建立连接,然后将请求发送到数据库,数据库执行操作,然后将结果集返回.所以在程序中,要尽量晚的与数据库建立连接,并且 ...

  9. Echarts在JavaWeb中与后台的交互实现

    本Web系统后台框架是:Spring+SpringMVC+Mybatis+Shiro+Maven.完整系统搭建的配置过程见上一篇文章:基于Spring+SpringMVC+Mybatis的Web系统搭 ...

随机推荐

  1. C++单链表反转、两有序链表合并仍有序

    1 #include<iostream> 2 3 struct Node 4 { 5 int data; 6 Node *next; 7 }; 8 9 typedef struct Nod ...

  2. docker镜像常用操作的基本命令

    1.拉取/下载镜像 docker pull 镜像名称       (可以从网易云镜像中心获取要下载的镜像) 2.查看已经下载的镜像 docker images 3.删除本地镜像 docker rmi ...

  3. 5. vue常用高阶函数及综合案例

    一. 常用的数组的高阶函数 假设, 现在有一个数组, 我们要对数组做如下一些列操作 1. 找出小于100的数字: 2. 将小于100的数字, 全部乘以2: 3. 在2的基础上, 对所有数求和: 通常我 ...

  4. 处理XML数据应用实践

    摘要:GaussDB(DWS)支持XML数据类型及丰富的XML解析函数,可实现关系数据和XML数据的映射管理功能. XML概述 XML是可扩展的标识语言(eXtensible Markup Langu ...

  5. 第七届蓝桥杯JavaB组——第7题剪邮票

    题目: 剪邮票 如[图1.jpg], 有12张连在一起的12生肖的邮票. 现在你要从中剪下5张来,要求必须是连着的. (仅仅连接一个角不算相连) 比如,[图2.jpg],[图3.jpg]中,粉红色所示 ...

  6. Kubernetes-5.Pod资源控制器(1)

    docker version:20.10.2 kubernetes version:1.20.1 本文概述Kubernetes Pod资源控制器的ReplicaSet.Deployment.Daemo ...

  7. loadrunner学习笔记一

    这篇笔记主要是针对一个具体的loadrunner脚本里面出现的方法进行解释,具体脚本如下: ` Action() { char *transactionName = "Test"; ...

  8. 《PYTHON机器学习及实践-从零开始通往KAGGLE竞赛之路》 分享下载

    转: <PYTHON机器学习及实践-从零开始通往KAGGLE竞赛之路> 分享下载 书籍信息 书名: PYTHON机器学习及实践-从零开始通往KAGGLE竞赛之路 标签: PYTHON机器学 ...

  9. .net 开源模板引擎jntemplate 实战演习:基础篇之入门

    一.简介 模板引擎是Web开发中非常重要的一环,它负责将页面上的动态内容呈现出最终的结果展现给前端用户,在asp.net mvc中,我们最熟悉的就是Razor了,作为官方的视图引擎(视图引擎不等同于模 ...

  10. POJ-2502(Dijikstra应用+最短路)

    Subway POJ-2502 这里除了直接相连的地铁站,其他图上所有的点都要连线,这里是走路的速度. 记住最后的结果需要四舍五入,否则出错. #include<iostream> #in ...