前言
前阵子接了个小项目,要做个微信小程序。逻辑方面十分简单,教科书般的工单系统。不过由于我对于后端前端完全没有学习基础,语言至今只学过C/C++的基础,终究还是花了一个多星期才做出beta版。虽然本地的确能跑了,但是估计还是有不少问题。在此记录下流程,以便后期修改时能立刻想起来。同时分享出来作为一个“起码跑的起来”的例子,以供大家参考指正。
本人能力有限,如有错误或不规范之处,感谢指出。
思路
一个简单的 C/S 结构就可以解决这个问题:
客户端发送信息给服务器,服务器进行处理,返回客户端需求的数据,之后由小程序显示出来
所以我们需要一个服务器来接受请求,一个数据库用来存放数据,一组代码来操作数据库和接受到的请求。
开发工具
服务器使用Tomcat 8.0.44 , 后端开发使用Eclipse Oxygen Release (4.7.0) , 小程序开发使用微信web开发者工具1.02 , 数据库使用MySQL 5.6.44
基本流程
Q:小程序如何提交请求呢?
A:利用wx.request和wx.uploadFile API提交给服务器。
Q:服务器如何才能获取小程序提交的请求?
A: 使用servlet获取小程序提交的请求。
Q: 我现在成功获取到了小程序发送来的数据,可是想保存在数据库里,该怎么办呢?
A: 使用JDBC连接数据库从而在服务器代码中将获取的数据存入数据库中。
数据库
首先在MySQL 中创建出相应数据库和表。
如:
CREATE TABLE USER
(
username varchar(16) primary key ,
password varchar(24) ,
name varchar(16),
permission tinyint(1) ,
phone char(11),
accept BOOL
);
服务端
选择了Servlet 用作服务器接收小程序请求。配置了web.xml后则可在 创建出的Servlet文件中的doGet 和 doPost 函数中对接收到的数据进行处理了。
示例代码(查询数据库中内容):
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// 修改编码为utf-8 用于显示中文
// response.setContentType("text/html;charset=utf-8");
response.setContentType("application/json; charset=utf-8");
// 设置响应头允许ajax跨域访问
response.setHeader("Access-Control-Allow-Origin", "*");
// 星号表示所有的异域请求都可以接受
response.setHeader("Access-Control-Allow-Methods", "GET,POST");
// ——————————————————————————
// 连接和注册数据库
// JDBC 驱动名及数据库 URL
String DB_URL = "jdbc:mysql://localhost:3306/working?characterEncoding=utf8";
// 数据库的用户名与密码
String USER = "root";
String PASS = "password";
Connection conn = null;
Statement stmt = null;
try {
// 注册 JDBC 驱动
Class.forName("com.mysql.jdbc.Driver");
// 打开链接
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// 实例化Statement对象
stmt = conn.createStatement();
//
// ————————————————————————————
// 用于接受客户端传递的数据
String cData = request.getParameter("data");
// 如果是获取数据的指令
if (cData.equals("G")) {
// 执行查询
String sql;
sql = "select * from worklist";
ResultSet rs = stmt.executeQuery(sql);
List < String > Wno = new ArrayList < String > ();
List < String > Wstate = new ArrayList < String > ();
List < String > Wtitle = new ArrayList < String > ();
List < String > Wcreater = new ArrayList < String > ();
List < String > Wworker = new ArrayList < String > ();
// 回送数据 格式为json
int i = 0;
while (rs.next()) {
i++;
Wcreater.add("\"" + rs.getString("creater") + "\"");
Wworker.add("\"" + rs.getString("worker") + "\"");
Wno.add("\"" + rs.getString("no") + "\"");
Wstate.add("\"" + rs.getString("state") + "\"");
Wtitle.add("\"" + rs.getString("title") + "\"");
}
// 返回json格式数据
response.getWriter().write("{\"no\": " + Wno + " ,");
response.getWriter().write("\"state\": " + Wstate + " ,");
response.getWriter().write("\"creater\": " + Wcreater + " ,");
response.getWriter().write("\"worker\": " + Wworker + " ,");
response.getWriter().write("\"title\": " + Wtitle + "}");
System.out.print("返回" + i + "份工单数据成功\n");
// 完成后关闭结果集
rs.close();
}
// 完成后关闭实例,释放连接
stmt.close();
conn.close();
}catch (SQLException se) {
// 处理 JDBC 错误
se.printStackTrace();
} catch (Exception e) {
// 处理 Class.forName 错误
e.printStackTrace();
} finally {
// 关闭资源
try {
if (stmt != null) stmt.close();
} catch (SQLException se2) {} // 关闭连接
try {
if (conn != null) conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
}
这里需要注意的是三方(数据库,后端,前端)的编码一定要统一,不然一定会有乱码;
同时,回传的数据最好使用json格式,否则小程序读取数据会十分麻烦。
客户端
小程序方面则可以调用微信封装的API wx.request对服务器进行请求数据.
js代码如下:
var temp_this = this;
wx.request({
url: 'http://localhost/working/QuestionList',
data: {
data: 'G',
},
header: {
'content-type': 'application/json'
},
method: 'get',
dataType: 'json',
responseType: 'text',
success: function(res) {
console.log(res.data)
console.log("向服务器请求成功")
// 将服务端数据存储在本地
temp_this.setData({
no: res.data.Wno,
state: res.data.Wstate,
creater: res.data.Wcreater,
worker: res.data.Wworker,
title: res.data.Wtitle
});
},
})
小程序中要注意的则是: 定义一个临时指针指向this,否则在wx.request函数里无法直接调用this。
到了这时候,已经实现了客户端和服务器的通信,小程序具备了雏形。
上传图片
之后甲方需求上传相应图片,这部分和之前的内容就不太一样了——不能通过数据库直接实现(硬要说利用数据库实现也可以,利用数据库存储二进制文件,但是效率极差,故考虑直接存储在服务器上利用URL直接访问)。
在数据库中添加了图片数量字段,由于本程序不考虑安全性问题,故使用了有规律的目录进行存储图片,节省数据库存储目录的字段,直接利用工单号进行构建。
用到了fileupload这个包
fileupload下载
代码如下:
package com.temp.temp.temp;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import java.util.*;
/**
* Servlet implementation class getImage
*/
@WebServlet("/getImage")
public class getImage extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public getImage() {
super();
// TODO Auto-generated constructor stub
}
// 全局的 no 用于确定当前工单
private String no = "";
// 更新照片数量函数
private void sqlUpdate(int flag) {
// ——————————————————————————
// 连接和注册数据库
// JDBC 驱动名及数据库 URL
String DB_URL = "jdbc:mysql://localhost:3306/working?useUnicode=true&characterEncoding=utf-8";
// 数据库的用户名与密码
String USER = "root";
String PASS = "young1225";
Connection conn = null;
Statement stmt = null;
try{
// 注册 JDBC 驱动
Class.forName("com.mysql.jdbc.Driver");
// 打开链接
conn = DriverManager.getConnection(DB_URL,USER,PASS);
// 执行查询
// 实例化Statement对象
stmt = conn.createStatement();
//
// ————————————————————————————
// 更新语句——————————
String update;
// 每次对于不同的插入,在数据库中对于计数器自增1
if(flag == 1)
update = "update working set WdevPhotocount = WdevPhotocount + 1 where no = " + no;
else
update = "update working set WwrkPhotocount = WwrkPhotocount+ 1 where no = " + no;
System.out.println(update);
stmt.executeUpdate(update);
// 完成后关闭
stmt.close();
conn.close();
}catch(SQLException se){
// 处理 JDBC 错误
se.printStackTrace();
}catch(Exception e){
// 处理 Class.forName 错误
e.printStackTrace();
}finally{
// 关闭资源
try{
if(stmt!=null) stmt.close();
}catch(SQLException se2){
}// 关闭连接
try{
if(conn!=null) conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// doPost
System.out.print("成功进入GetImage\n");
// 存取form中其他数据
String ino = "";
String permission ="";
//获得磁盘文件条目工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//文件上传处理
ServletFileUpload upload = new ServletFileUpload(factory);
try {
//可以上传多个文件
List<FileItem> list = (List<FileItem>)upload.parseRequest(request);
for(FileItem item : list){
//如果获取的 表单信息是普通的 文本 信息
if(item.isFormField()){
//获取用户具体输入的字符串,因为表单提交过来的是 字符串类型的
String value = item.getFieldName() ;
// System.out.print("value:" + value+item.getString("UTF-8")+"\n");
// 进行判断,为每一个键值存储属性
if(value.equals("no"))
{
no = new String(item.getString("UTF-8"));
}
else if(value.equals("permission"))
{
permission = new String(item.getString("UTF-8"));
}
else if(value.equals("ino"))
{
ino = new String(item.getString("UTF-8"));
}
}
else{
//获取文件需要上传到的路径
@SuppressWarnings("deprecation")
String path = request.getRealPath("/temp/0" + no);
// 新建目录
File file=new File(path);
if(!file.exists()){
file.mkdirs();
}
factory.setRepository(new File(path));
//设置 缓存的大小
factory.setSizeThreshold(4096*1024*1024) ;
// 构造文件名
String filename = permission+"_0"+ino+".jpg";
//写到磁盘上
item.write( new File(path,filename) );// 写入文件至服务器
System.out.println("上传成功:"+filename);
response.getWriter().print(path+"\\"+filename);//将路径返回给客户端
// 统计照片数量
if(permission.equals("dev"))
sqlUpdate(1);
else
sqlUpdate(0);
}
}
} catch (Exception e) {
System.out.println("上传失败");
response.getWriter().print("上传失败:"+e.getMessage());
}
}
}
而在微信小程序这边,只需要调用wx.uploadFile 把相应数据丢给服务器的上述代码进行处理即可。
代码:
// 遍历图片数组,并上传
for(var i = 0 ; i < this.data.images.length ; i++)
{
// 上传图片
wx.uploadFile({
url: 'http://localhost/working/imageOpt',
filePath: temp_this.data.images[i],
name: 'file',
header: {},
formData: {
'permission': ((wx.getStorageSync("userPermission")) == 1 ? '开发者' : '施工者'),
'wno': temp_this.data.no,
'ino': ''+i,
},
success: function (res) {
console.log(res.data);
},
})
}
尾声
综上,构建一个跑的起来的微信小程序的流程就完成了,关于小程序正式上线的部分在网上则是一搜一大把,在此不再赘述。
以及关于微信小程序的详情可以参考 微信小程序开放文档