android访问服务端的网络接口,Android通过Web与后台数据库交互

2020.06.23 更新

1 背景

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

以后逐步改用Spring框架,优化MySQL,进一步部署Tomcat等等,现在项目刚刚起步,还有很多不懂的东西,得慢慢来......

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

2 开发环境

本地Win

服务器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不能使用太弱的密码.

如果出现如下提示:

7dac4433972ff5376ca059c895721479.png

则说明密码太弱了,请使用一个更高强度的密码.

3.1.4 允许外部访问

use mysql;

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

这个可以根据自己的需要去修改,host='%'表明允许所有的ip登录,也可以设置特定的ip,若使用host='%'的话建议新建一个用户配置相应的权限.

3.1.5 配置防火墙(可选)

一般来说需要在对应的云厂商的防火墙配置中开启响应端口,如图:

f0d297d6ecc0251fadcf61979c967d02.png

6b2a0f8715c2d10d73183ebe090c8995.png

3a39a0ca6e5f4d3ce56eac8d4c3df226.png

abb6669cc6aa53342cff06d9589845f9.png

其中授权对象可以根据自己的需要更改,0.0.0.0/0表示允许所有的ip.

3.2 安装Tomcat

3.2.1 下载并上传到服务器

先去官网下载,下载后上传文件到服务器:

2baffc6ac6dbc9e2b8af0c0a8e9a94d5.png

eedbab6a35d44b980d5a9d7a8c928399.png

笔者使用的是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文件,一般只需修改

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

需要的话自行更改.

笔者这么懒的是不会更改的.

3.2.4 启动

运行bin目录下的startup.sh:

cd bin

./startup.sh

3.2.5 测试

浏览器输入:

服务器IP:端口

若出现:

7ac0e3612c5675fec68e15d20ac2a2e4.png

则表示成功.

3.2.6 开机启动(可选)

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

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

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

4 建库建表

创建用户表,这里简化操作(好吧笔者就是喜欢偷懒)就不创建新用户不授权了.

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

4.1 创建user.sql

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

7c50bb8642a522bb6d1422aae21aa0e4.png

5 后端部分

5.1 创建项目

选择Web Application:

da649eed22124e9536b010058e0de685.png

e3c240f9572b4a9f5883a911483b846d.png

5.2 添加依赖库

创建一个叫lib的目录:

f915a403e21e8eef9fff0de5321f73be.png

添加两个jar包(jar包在文末提供下载链接):

mysql-connector-java-8.0.17.jar

javax.servlet-api-4.0.1.jar

a350a1f0c2702349239e2712e5c899c9.png

打开Project Structure:

f11cc7040a03eefedbbb1d4e34f7b270.png

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

ee1b20fbd19d256d172a2b65126122ed.png

选择刚才新建的lib下的两个jar包:

35f05e93ed491392e69d59fbc5a0afa0.png

打勾,apply:

c3ed54c335e87b66477336e4a46342cd.png

5.3 创建包与类

总共4个包

com.servlet:用于处理来自前端的请求,包含SignUp.java,SignIn.java

com.util:主要功能是数据库连接,包含DBUtils.java

com.entity:实体类,包含User.java

com.dao:操作用户类的类,包含UserDao.java

43a7dae98dd0643cc53ae3748152065f.png

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进去,但前端显示注册失败(这个bug笔者找了是真的久......)

5.7 SignIn与SignUp

servlet包的SingIn类用于处理登录,调用JDBC查看数据库是否有对应的用户.

SignUp类用于处理注册,把User添加到数据库中.

目前使用的是HTTP连接,后期会考虑添加HTTPS支持.

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")

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

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

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

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">

SignIn

com.servlet.SingIn

SignUp

com.servlet.SignUp

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

<servlet-name>是Servlet的名字,最好与类名一致

<servlet-class>是Servlet类的位置

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

SignIn

/SignIn

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

5.9 Hello.html测试文件

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

Welcome

Hello web.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值