我的云图库
** 以下的基于安卓客户端和linux服务端,服务端将数据转化成json数据,在安卓端进行接受以及转化成我们需要的数据的类型。**
前提
1.一台装有tomcat(配置好远程部署)的服务器(本机也可以,访问的地址要改成 10.0.2.2,绝对不能是127.0.0.1或者localhost,如果处在局域网内要根据实际情况调整)。
2.需要的jar包:谷歌公司提供的Gson.jar包,以及web服务端所会用到的common-io和common-fileupload架包。这不提供链接,自己去maven官网上面下载。
3.会基础的Java和web知识。。。
正文**
一,首先构建服务端的代码,将客户端要访问的数据转化为json数据类型。
1.首先构造两个类,class类和image类
class类:
package android.Bean;
public class ClassBean {
private int ID;
private String ClassName;
public int getID() {
return ID;
}
public String getClassName() {
return ClassName;
}
public void setID(int ID) {
this.ID = ID;
}
public void setClassName(String className) {
ClassName = className;
}
}
imagebean的类:byte数组是用来存放图片的二进制数据,在客户端进行转化
package android.Bean;
public class ImageBean {
private int id;
private String Imagename;
private int classid;
private String filepath;
private byte[] data;
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public void setId(int id) {
this.id = id;
}
public void setImagename(String imagename) {
Imagename = imagename;
}
public void setClassid(int classid) {
this.classid = classid;
}
public void setFilepath(String filepath) {
this.filepath = filepath;
}
public int getId() {
return id;
}
public String getImagename() {
return Imagename;
}
public int getClassid() {
return classid;
}
public String getFilepath() {
return filepath;
}
}
2,与数据库的交互的操作,数据库的连接的代码不予展示(Java基本功)
package servlet;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import android.Bean.ClassBean;
import android.Bean.ImageBean;
import utils.jdbcutils;
public class ClassDao {
public static List<ClassBean> getBigShopList() {
String sql = "Select * From classinfo order by id asc";
QueryRunner runner = new QueryRunner();
Connection conn = null;
List<ClassBean> userList = null;
try {
conn = jdbcutils.getConn();
userList = runner.query(conn, sql, new BeanListHandler<ClassBean>(ClassBean.class));
} catch (Exception e) {
e.printStackTrace();
} finally {
jdbcutils.tryClose(null, conn);
}
return userList;
}
public static Boolean AddClass(String classname) {
Statement stmt = null;
Connection conn = null;
int row = 0;
String sql = "insert into classinfo(classname) values(?)";
try {
conn = jdbcutils.getConn();
stmt = conn.createStatement();
PreparedStatement ps = conn.prepareStatement(sql);
// 对SQL语句中的第1个参数赋值 g
ps.setString(1, classname);
row = ps.executeUpdate();
ps.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
jdbcutils.tryClose(stmt, conn);
}
if (row > 0) {
return true;
} else {
return false;
}
}
public static List<ImageBean> getImage(String classid) {
String sql = "Select * From image where classid="+classid;
System.out.println(sql);
QueryRunner runner = new QueryRunner();
Connection conn = null;
List<ImageBean> userList = null;
try {
conn = jdbcutils.getConn();
userList = runner.query(conn, sql, new BeanListHandler<ImageBean>(ImageBean.class));
} catch (Exception e) {
e.printStackTrace();
} finally {
jdbcutils.tryClose(null, conn);
}
return userList;
}
public static ClassBean getCLass(String classid) {
String sql = "Select * From classinfo where id=" + classid;
QueryRunner runner = new QueryRunner();
Connection conn = null;
List<ClassBean> userList = null;
try {
conn = jdbcutils.getConn();
userList = runner.query(conn, sql, new BeanListHandler<ClassBean>(ClassBean.class));
} catch (Exception e) {
e.printStackTrace();
} finally {
jdbcutils.tryClose(null, conn);
}
ClassBean bean = null;
for (ClassBean item : userList) {
bean = item;
}
return bean;
}
public static void SaveWork(Map<String, String> dataMap) {
// TODO Auto-generated method stub
Connection conn = null;
PreparedStatement pstmt = null;
String classid = String.valueOf(dataMap.get("classid"));
String filename = String.valueOf(dataMap.get("filename"));
String filepath = String.valueOf(dataMap.get("filepath"));
StringBuffer insertSQL = new StringBuffer();
insertSQL.append("Insert Into image(");
insertSQL.append("classid,filepath,imagename");
insertSQL.append(") values(");
insertSQL.append("?,?,? ");
insertSQL.append(")");
try {
conn = jdbcutils.getConn();
pstmt = conn.prepareStatement(insertSQL.toString());
// 为SQL语句?进行赋值的操作。
pstmt.setString(1, classid);
pstmt.setString(2, filepath);
pstmt.setString(3, filename);
// 执行SQL语句。
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
jdbcutils.tryClose(pstmt, conn);
}
}
}
3,servlet代码(主要做数据的处理以及响应)
package servlet;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import android.Bean.ClassBean;
import android.Bean.ImageBean;
import utils.WebUtil;
import utils.jdbcutils;
/**
* Servlet implementation class ClassServlet
*/
public class ClassServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
String task = request.getParameter("task");
if (task.equals("select")) {
//挑选出类别
this.doSelect(request, response);
} else if (task.equals("insert")) {
//类别的增加操作
this.doAdd(request, response);
} else if (task.equals("showImage")) {
//页面跳转,用于客户端的webview
this.doshowImage(request, response);
} else if (task.equals("imageSelect")) {
//获取图片的所有数据的操作
this.doselectimage(request, response);
} else if (task.equals("insertDel")) {
//文件的上传操作
this.insertDel(request, response);
}
}
private void doselectimage(HttpServletRequest request, HttpServletResponse response) throws IOException {
String classid = request.getParameter("value");
List<ImageBean> list = ClassDao.getImage(classid);
for(ImageBean bean:list) {
System.out.println("***********************");
ServletContext context = this.getServletContext();
String uploadDir = context.getRealPath("/uploadfiles/")+bean.getFilepath();
bean.setData(jdbcutils.image2byte(uploadDir));
}
PrintWriter out = response.getWriter();
if(list.size()==0) {
WebUtil.printJson("", out);
}else {
WebUtil.printJson(list, out);
}
out.flush();
out.close();
}
private void doshowImage(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String classid = request.getParameter("classid");
ClassBean bean = ClassDao.getCLass(classid);
request.setAttribute("bean", bean);
request.getRequestDispatcher("jsp/Work_edit.jsp").forward(request, response);
}
private void doAdd(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();
String str = request.getParameter("value");
Boolean flag = ClassDao.AddClass(str);
WebUtil.printJson(flag, out);
out.flush();
out.close();
}
private void doSelect(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();
List<ClassBean> list = ClassDao.getBigShopList();
WebUtil.printJson(list, out);
out.flush();
out.close();
}
protected void insertDel(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("UTF-8");// 传值编码
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
Map<String, String> dataMap = new HashMap<String, String>();
try {
List<DiskFileItem> list = fileUpload.parseRequest(request);
for (DiskFileItem fileItem : list) {
boolean isFormField = fileItem.isFormField();
if (isFormField == true) {
// 表示是表单的普通元素
String field_Name = fileItem.getFieldName();
String field_Value = fileItem.getString("UTF-8");
dataMap.put(field_Name, field_Value);
} else {
// 表示是表单的上传元素
String filename = fileItem.getName();
if (filename != null && filename.equals("") == false) {
String filepath = WebUtil.getTimeStamp() + "_" + filename;
dataMap.put("filename", filename);
dataMap.put("filepath", filepath);
InputStream inputStream = fileItem.getInputStream();
ServletContext context = this.getServletContext();
String uploadDir = context.getRealPath("/uploadfiles");
// uploadfiles
String sss = uploadDir + "/" + filepath;
OutputStream outputStream = new FileOutputStream(uploadDir + "/" + filepath);
int i = 0;
byte[] byteArray = new byte[10240];
while ((i = inputStream.read(byteArray)) != -1) {
outputStream.write(byteArray, 0, i);
}
outputStream.flush();
// 关闭流
inputStream.close();
outputStream.close();
}
}
}
// 2:将数据写入到数据库中。
ClassDao.SaveWork(dataMap);
} catch (FileUploadException e) {
e.printStackTrace();
}
out.flush();
out.close();
}
}
二,构建客户端的代码,客户端主要是产生请求和对json数据进行解析
1,对于客户端,也需要两个class的类和imageclass的类,用来使用gson的数据进行数据转化
2,对于客户端,我并未选择把数据库的操作放在客户端,一方面来说,对于数据库的存储操作,在安卓的客户端会比较困难(是我太菜了),另一方方面,如果把数据库放在客户端,外面的人可对你的app进行反编译,获取你的数据库的连接的方式,安全性太低,所以,对于安卓的开发来说,一般的数据操作基本是放在服务端,安卓端所要做的所要做的只是对json数据或者sml数据进行分析。
3,对于mianactivity这个Java的使用,我采用的是使用多线程和handler的方式,我采用的利用子线程来获取数据,在通过message对数据进行包装,然后同通过handler的msg的发送机制,在handler里面对数据进行分析,值得一提的是,网络上的的大部分的数据的网络使用的是httpclient,并且没有使用线程,我i不知道是啥原因,反正我是运行不了的。(话不多说,大部分解读,我放在注释里面了)
数据的请求的代码:(只简单的示例一小部分)
public static String getJSONSelect(String task) throws Exception {
StringBuilder sb = new StringBuilder();
String path = "你自己的url";
Log.i("***********==",path);
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
InputStream inStream = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
reader.close();
return sb.toString();
}
return null;
}
MainActivity的代码
package com.example.images;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
List<Map<String, Object>> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ListView listView = findViewById(R.id.listview);
list = new ArrayList<Map<String, Object>>();
//对获取到的数据进行分析
final Handler handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
//常规的适配器操作
ClassBean[] array = new Gson().fromJson(msg.obj.toString(), ClassBean[].class);
List<ClassBean> Classlist = Arrays.asList(array);
for(ClassBean bean:Classlist){
Map<String,Object> map=new HashMap<String, Object>();
map.put("name",bean.getClassName());
map.put("classid",bean.getID());
list.add(map);
}
SimpleAdapter simpleAdapter = new SimpleAdapter(MainActivity.this, list, R.layout.cell,
new String[]{"name","classid"}, new int[]{R.id.text1,R.id.classid});
listView.setAdapter(simpleAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Map<String, Object> map = list.get(position);
// Toast.makeText(MainActivity.this, String.valueOf(map.get("classid")), Toast.LENGTH_SHORT).show();
Intent intent=new Intent(MainActivity.this,ImageActivity.class);
Bundle bundle=new Bundle();
bundle.putCharSequence("classid",String.valueOf(map.get("classid")));
intent.putExtras(bundle);
startActivity(intent);
}
});
}
}
};
//对类别进行添加,简单的activity操作
Button button=findViewById(R.id.buttonAdd);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MainActivity.this,AddActivity.class);
startActivity(intent);
}
});
//在这里使用子线程来对数据进行获取,采用用msg将数据转发到主线陈
new Thread(new Runnable(){
@Override
public void run() {
String str="";
try {
str=Utils.getJSONSelect("select");
Log.i("**********************",str);
} catch (Exception e) {
e.printStackTrace();
}
Message msg=new Message();
msg.what=1;
msg.obj=str;
handler.sendMessage(msg);
}
}).start();
}
}
程序运行的结果:
4,imageactivity的操作,这里的数据转化值得一说,设计到两个数据类型的转化,原本我是想通过获取到的数据来进行对图片的二次获取,但是,在写完以后,我发现,对于这种代码,太过复杂,所以,我采用了把数据放在byte数组里面,然后对数据进行分析,将byte数组里面的数据转化为bitmap数据,然后对数据进行转化,把bitmap数据在适配器里面对数据转化为可显示的数据。
package com.example.images;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ImageActivity extends AppCompatActivity {
String Url = "";
List<Map<String, Object>> list;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.imagemain);
Log.i("*********************", "进入查看图像");
final Intent intent = getIntent();
final Bundle bundle = intent.getExtras();
final ListView listView = findViewById(R.id.listview2);
final String classid = bundle.getString("classid");
Log.i("***********===", classid);
//常规的数据处理
final Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
list=new ArrayList<Map<String, Object>>();
if (msg.what == 6) {
ImageBean[] array = new Gson().fromJson(msg.obj.toString(), ImageBean[].class);
List<ImageBean> Classlist = Arrays.asList(array);
for(ImageBean bean:Classlist){
Map<String,Object> map=new HashMap<String, Object>();
//byte数组转化为bitmap数据
Bitmap bitmap = BitmapFactory.decodeByteArray( bean.getData(), 0, bean.getData().length);
map.put("name","名称:"+bean.getImagename()+"\n"+"地点:无"+"\n"+"描述:无");
map.put("image",bitmap);
list.add(map);
}
SimpleAdapter simpleAdapter = new SimpleAdapter(ImageActivity.this, list, R.layout.imagecell,
new String[]{"image","name"}, new int[]{R.id.image123465,R.id.text123465});
//使用setviewBinder的对数据进行转化成可显示的图片
simpleAdapter.setViewBinder(new SimpleAdapter.ViewBinder() {
@Override
public boolean setViewValue(View view, Object data,
String textRepresentation) {
if( (view instanceof ImageView) & (data instanceof Bitmap) ) {
ImageView iv = (ImageView) view;
Bitmap bm = (Bitmap) data;
iv.setImageBitmap(bm);
return true;
}
return false;
}
});
listView.setAdapter(simpleAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Map<String, Object> map = list.get(position);
Toast.makeText(ImageActivity.this, String.valueOf(map.get("name")), Toast.LENGTH_SHORT).show();
}
});
}else {
Toast.makeText(ImageActivity.this, "此类没有图片", Toast.LENGTH_SHORT).show();
}
}
};
Button button = findViewById(R.id.buttonImage);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("*****************", "进入图片添加");
Intent intent1 = new Intent(ImageActivity.this, ImageAddActivity.class);
intent1.putExtras(bundle);
startActivity(intent1);
}
});
//依旧采用子线程对数据进行获取和分析
new Thread(new Runnable() {
@Override
public void run() {
String str = "";
Log.i("***********===2", "进入获取数据");
try {
str = Utils.getJSONSelect("imageSelect&value=" + classid);
Log.i("******=====*******", classid);
} catch (Exception e) {
e.printStackTrace();
}
//获取到的数据必定大于10
Message msg = new Message();
if(str.length()>10){
msg.what = 6;
msg.obj = str;
}else{
msg.what = 0000;
}
Log.i("******=====*******", String.valueOf(str.length()));
handler.sendMessage(msg);
}
}).start();
}
}
运行截图:
5,对MainActivity的里面的添加的类的addactivity
程序代码:
package com.example.images;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class AddActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addcell);
Button button=findViewById(R.id.buttonAdd2);
final EditText editText=findViewById(R.id.addtext);
final Handler handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if(msg.what==2){
Toast.makeText(AddActivity.this, "添加数据成功", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(AddActivity.this, "添加数据失败", Toast.LENGTH_SHORT).show();
}
}
};
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final String str= String.valueOf(editText.getText());
Log.i("*************",str);
new Thread(new Runnable(){
@Override
public void run() {
Boolean flag=false;
try {
flag=Utils.addClass("insert&value="+str);
} catch (Exception e) {
e.printStackTrace();
}
Message msg=new Message();
if(flag==true){
msg.what=2;
msg.obj=flag;
}else{
msg.what=4;
msg.obj=flag;
}
handler.sendMessage(msg);
}
}).start();
}
});
Button button1=findViewById(R.id.buttonAdd3);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(AddActivity.this,MainActivity.class);
startActivity(intent);
}
});
}
}
程序结果:
6,接下来是图片的添加的activity,我是直接用webview来实现,采用的是隐式的intent用两个activity实现
跳转的代码:
ImageAddActivity
package com.example.images;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class ImageAddActivity extends AppCompatActivity {
String Url;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent=getIntent();
Bundle bundle=intent.getExtras();
String classid=bundle.getString("classid");
//连接不展示
Url = "你的url"+classid;
Log.i("====================",Url);
intent = new Intent(ImageAddActivity.this,WebViewActivity.class);
Bundle bundle1=new Bundle();
bundle1.putCharSequence("Url",Url);
//Uri uri=Uri.parse(Url);
//intent.setData(uri);
intent.putExtras(bundle1);
try {
startActivity(intent);
}catch (Exception e){
e.printStackTrace();
}
}
}
采用的是activity的跳转的模式
WebViewActivity代码:
package com.example.images;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class WebViewActivity extends Activity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);
//获得浏览器webView控件
webView = findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowContentAccess(true);
//得到鼠标点击之后的intent
Intent intent ;
intent=getIntent();
Bundle bundle=intent.getExtras();
String urlString=bundle.getString("Url");
webView.loadUrl(urlString);//加载
//手机默认浏览器打开,为了通过WebView打开网页,设置
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("http:") || url.startsWith("https:")) {
view.loadUrl(url);
return false;
}
view.loadUrl(url);
return true;
}
});
}
}
运行截图:
总结
对于云图库的构建,最最主要的就是安卓访问服务器,然后对json数据进行解析,再次,使用多线程的数据访问的方式,把子线程的数据用handler的msg机制,把需要的消息传到主线程再对其进行深度解析,对于数据的类型的一定要注意使用setViewBinder这个方法,绝对不可以直接再路径里面写bitmap,他显示的只是一个内存地址,最后,其实可以把Javaweb和安卓结合,就是隐式的intent的应用。