目录
前言
在上一篇博客中 开发Windows物流管理系统——(一)前期准备 我们对物流管理系统有了一定的分析,这次就对其中的功能做一下具体的 代码实现。
要特别指出的是,本项目是团队合作项目,在此仅展示鄙人完成的部分,剩下的请移步其它组员处:
进行查看;或前往Github查看。在导入本项目代码后,需要同时导入MySQL的Java驱动。
安全起见,代码中涉及到的隐私信息都已经做了模糊处理,项目遵循GPL-3.0 License,若存在任何资源的版权问题,请先联系我们,侵权必删。
工作流程
作为后端,首先需要处理前端的需求,根据需要判断逻辑,连接数据库并操作,最后返回操作的结果或者状态给前端。
因此,需要三个类,分别是Response类,用来被前端调用,并传入参数;还有DatabaseOperation类,用来被Response类调用,传入参数后直接操作数据库;最后有Result类,用来保存结果,类似结构体,方便数据多的时候前端去查看。
数据库端的组员提供了数据库的结构,有三张表,分别是买家表,字段是UID、Password和Address;还有卖家表,字段和买家相同;最后有物流表,字段有ID、sellerID、customerID。
鄙人主要负责数据库的增、改、查部分,根据前端组员的需要,细化为登录方法、注册方法、查询物流表方法、更新个人信息方法。
Result部分
先生成用于存放多项数据的类,方便后文使用。
类中有三个私有变量,分别是用于存放ID、UID、Address的。提供了构造时直接初始化的方法,也提供了使用getter和setter的方法。
public class Result {
Result(){
}
Result(String ID, String UID, String address){
this.ID = ID;
this.UID = UID;
this.Address = address;
}
private String ID;
private String UID;
private String Address;
public String getID() {
return ID;
}
public String getUID() {
return UID;
}
public String getAddress() {
return Address;
}
public void setID(String ID) {
this.ID = ID;
}
public void setUID(String UID) {
this.UID = UID;
}
public void setAddress(String address) {
this.Address = address;
}
}
Response部分
最初创建Response类。
枚举变量
先声明全局枚举变量
public static enum ResponseState{
Error,
DatabaseError,
DriverNotFound,
IncorrectUID,
ExistedUID,
IncorrectPassword,
PasswordMismatched,
IncorrectAddress,
Done,
}
由于前端组员的要求,传入角色的参数将使用int类型表示
//0--customer
//1--seller
login方法
前端传入参数有用户身份,UID值,password密码,检测UID是否符合11位长度、密码是否符合6至20位长度,若不符合则报错;若符合则根据身份不同,调用DatabaseOperation类的matchPassword方法,传入不同的参数,交由后文来与数据库打交道。
public static ResponseState login(
int role, String UID, String password){
if((UID == null) || (UID.length() != 11)){
return ResponseState.IncorrectUID;
}
else if((password == null) || (password.length() < 6 || password.length() > 20)){
return ResponseState.IncorrectPassword;
}
else if(role == 1){
try {
return DatabaseOperation.matchPassword("sellers", UID, password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
else if(role == 0){
try {
return DatabaseOperation.matchPassword("customers", UID, password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return ResponseState.Error;
}
register方法
类似上文,前端传入用户身份,UID值,address地址,password密码和passwordVerification二次输入密码。相较上文,多了一个address检测和passwordVerification检测。
public static ResponseState register(
int role, String UID, String address,
String password, String passwordVerification){
if((UID == null) || (UID.length() != 11)){
return ResponseState.IncorrectUID;
}
else if((password == null) || (password.length() < 6 || password.length() > 20)){
return ResponseState.IncorrectPassword;
}
else if(!password.equals(passwordVerification)){
return ResponseState.PasswordMismatched;
}
else if((address == null) || (address.length() < 1)){
return ResponseState.IncorrectAddress;
}
else if(role == 1){
try {
return DatabaseOperation.createUID("sellers", UID, password, address);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
else if(role == 0){
try {
return DatabaseOperation.createUID("customers", UID, password, address);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return ResponseState.Error;
}
query方法
此时用户已经登录,身份可信,所以不需要过多的检测,前端传入的用户身份,UID值可以直接调用。
public static ArrayList<Result> query(int role, String UID){
try {
return DatabaseOperation.queryDB(role, UID);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return new ArrayList<Result>();
}
updateInformation方法
和上文同理,但是前端传入的password和address仍需要检测。
public static ResponseState updateInformation(
int role, String UID, String address, String password){
if((password == null) || (password.length() < 6 || password.length() > 20)){
return ResponseState.IncorrectPassword;
}
else if((address == null) || (address.length() < 1)){
return ResponseState.IncorrectAddress;
}
else if(role == 1){
try {
return DatabaseOperation.updateUID("sellers", UID, password, address);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
else if(role == 0){
try {
return DatabaseOperation.updateUID("customers", UID, password, address);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return ResponseState.Error;
}
DatabaseOperation部分
此类中全部方法都与上文中的方法一一对应,请参照上文查看。
和上文类似,创建DatabaseOperation类。
声明全局变量
主要用于声明MySQL服务器信息
//we delete the private data below, you need to change it before using.
static String DatabaseURL = "jdbc:mysql://IP_ADDRESS_OR_DOMAIN_NAME:PORT/DATABASE_NAME?serverTimezone=Asia/Shanghai";
matchPassword方法
建立连接、状态和结果集,使用账号密码建立数据库连接,初始化SQL语句,传入对应参数,执行语句即可,若完成则返回Done状态,否则返回对应的Error状态,最后关闭刚才的连接、状态和结果集。
static public Response.ResponseState matchPassword(String table, String UID, String password) throws SQLException{
Connection databaseConnection = null;
PreparedStatement databaseStatement = null;
ResultSet databaseResult = null;
Response.ResponseState processState = Response.ResponseState.Error;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
databaseConnection = DriverManager.getConnection(DatabaseURL,
"USER_NAME", "PASSWORD");
String SQL = "select Password from " + table + " where UID = ?";
databaseStatement = databaseConnection.prepareStatement(SQL,
databaseResult.TYPE_SCROLL_INSENSITIVE, databaseResult.CONCUR_READ_ONLY);
databaseStatement.setString(1, UID);
databaseResult = databaseStatement.executeQuery();
if(databaseResult.next()){
if(databaseResult.getString(1).equals(password)){
processState = Response.ResponseState.Done;
}
else{
processState = Response.ResponseState.IncorrectPassword;
}
}
else{
processState = Response.ResponseState.IncorrectUID;
}
}
catch (SQLException e) {
processState = Response.ResponseState.DatabaseError;
}
catch (ClassNotFoundException e) {
processState = Response.ResponseState.DriverNotFound;
}
finally {
try {
assert databaseResult != null;
databaseResult.close();
assert databaseStatement != null;
databaseStatement.close();
assert databaseConnection != null;
databaseConnection.close();
}
catch(Exception e){
}
}
return processState;
}
createUID方法
和上文类似,先筛选出是否已经存在该UID,若存在则报错,否则执行插入语句。
static public Response.ResponseState createUID(String table, String UID, String password, String address) throws SQLException{
Connection databaseConnection = null;
PreparedStatement databaseStatement = null;
ResultSet databaseResult = null;
Response.ResponseState processState = Response.ResponseState.Error;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
databaseConnection = DriverManager.getConnection(DatabaseURL,
"USER_NAME", "PASSWORD");
String SQL = "select UID from " + table + " where UID = ?";
databaseStatement = databaseConnection.prepareStatement(SQL,
databaseResult.TYPE_SCROLL_INSENSITIVE, databaseResult.CONCUR_READ_ONLY);
databaseStatement.setString(1, UID);
databaseResult = databaseStatement.executeQuery();
if(databaseResult.next()){
processState = Response.ResponseState.ExistedUID;
}
else{
SQL = "insert into " + table + " (`UID`, `PassWord`, `Address`) values (?, ?, ?)";
databaseStatement = databaseConnection.prepareStatement(SQL,
databaseResult.TYPE_SCROLL_INSENSITIVE, databaseResult.CONCUR_UPDATABLE);
databaseStatement.setString(1, UID);
databaseStatement.setString(2, password);
databaseStatement.setString(3, address);
databaseStatement.executeUpdate();
processState = Response.ResponseState.Done;
}
}
catch (SQLException e) {
processState = Response.ResponseState.DatabaseError;
}
catch (ClassNotFoundException e) {
processState = Response.ResponseState.DriverNotFound;
}
finally {
try {
assert databaseResult != null;
databaseResult.close();
assert databaseStatement != null;
databaseStatement.close();
assert databaseConnection != null;
databaseConnection.close();
}
catch(Exception e){
}
}
return processState;
}
queryDB方法
初始化ArrayList类型变量,存储Result类。获取到结果后,遍历存入列表中,若无结果,则返回空列表。
static public ArrayList<Result> queryDB(int role, String UID) throws SQLException {
ArrayList<Result> queryResult = new ArrayList<Result>();
Connection databaseConnection = null;
PreparedStatement databaseStatement = null;
ResultSet databaseResult = null;
if(role == 1){
try{
Class.forName("com.mysql.cj.jdbc.Driver");
databaseConnection = DriverManager.getConnection(DatabaseURL,
"USER_NAME", "PASSWORD");
String SQL = "select ID, CustomerID, Address from packages, customers where packages.CustomerID = customers.UID AND SellerID = ?";
databaseStatement = databaseConnection.prepareStatement(SQL,
databaseResult.TYPE_SCROLL_INSENSITIVE, databaseResult.CONCUR_READ_ONLY);
databaseStatement.setString(1, UID);
databaseResult = databaseStatement.executeQuery();
while(databaseResult.next()){
queryResult.add(new Result(databaseResult.getString(1),
databaseResult.getString(2),
databaseResult.getString(3)));
}
}
catch (SQLException e) {
}
catch (ClassNotFoundException e) {
}
finally {
try {
assert databaseResult != null;
databaseResult.close();
assert databaseStatement != null;
databaseStatement.close();
assert databaseConnection != null;
databaseConnection.close();
}
catch(Exception e){
}
}
}
else{
try{
Class.forName("com.mysql.cj.jdbc.Driver");
databaseConnection = DriverManager.getConnection(DatabaseURL,
"USER_NAME", "PASSWORD");
String SQL = "select ID, SellerID, Address from packages, sellers where packages.SellerID = sellers.UID AND CustomerID = ?";
databaseStatement = databaseConnection.prepareStatement(SQL,
databaseResult.TYPE_SCROLL_INSENSITIVE, databaseResult.CONCUR_READ_ONLY);
databaseStatement.setString(1, UID);
databaseResult = databaseStatement.executeQuery();
while(databaseResult.next()){
queryResult.add(new Result(databaseResult.getString(1),
databaseResult.getString(2),
databaseResult.getString(3)));
}
}
catch (SQLException e) {
}
catch (ClassNotFoundException e) {
}
finally {
try {
assert databaseResult != null;
databaseResult.close();
assert databaseStatement != null;
databaseStatement.close();
assert databaseConnection != null;
databaseConnection.close();
}
catch(Exception e){
}
}
}
return queryResult;
}
updateUID方法
收到传入参数,直接执行对应的更新语句即可。
static public Response.ResponseState updateUID(String table, String UID, String password, String address) throws SQLException{
Connection databaseConnection = null;
PreparedStatement databaseStatement = null;
ResultSet databaseResult = null;
Response.ResponseState processState = Response.ResponseState.Error;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
databaseConnection = DriverManager.getConnection(DatabaseURL,
"USER_NAME", "PASSWORD");
String SQL = "update " + table + " set PassWord = ?, Address = ? where UID = ?";
databaseStatement = databaseConnection.prepareStatement(SQL,
databaseResult.TYPE_SCROLL_INSENSITIVE, databaseResult.CONCUR_UPDATABLE);
databaseStatement.setString(1, password);
databaseStatement.setString(2, address);
databaseStatement.setString(3, UID);
databaseStatement.executeUpdate();
processState = Response.ResponseState.Done;
}
catch (SQLException e) {
processState = Response.ResponseState.DatabaseError;
}
catch (ClassNotFoundException e) {
processState = Response.ResponseState.DriverNotFound;
}
finally {
try {
assert databaseResult != null;
databaseResult.close();
assert databaseStatement != null;
databaseStatement.close();
assert databaseConnection != null;
databaseConnection.close();
}
catch(Exception e){
}
}
return processState;
}
可以改进的地方
这次仍旧时间紧张,整体开发流程相对复杂,但是分工合作效率较高,相对完成度较好。尤其是数据库部署在云端,方便了数据的同步,极大地提高了应用的实用性。后续可以完善物流管理系统,引入商品类型,引入更多的物流种类等等,覆盖整个物流产业链。数据端可以增加更多用户,合理分配权限,提高安全性。如果有能力,可以尝试去做多端适配、打通生态。
补充内容
鄙人搭建了云服务器,并部署了MySQL服务,由于过程极为简单,便不再赘述,详情可以移步至上一篇博客 开发Windows物流管理系统——(一)前期准备 进行查看。
详细代码
本项目的全部源码以及打包程序均上传至GitHub,并附有说明文档,具体信息请前往Github查看,测试程序请前往Release下载,项目遵循GPL-3.0 License协议。