前面我们实现了微信消息界面的实现,这篇继续完善微信功能,实现微信通讯录界面
移动端微信通讯录界面功能实现
微信通讯录,头部是四个标签(不进行分组),下面是好友信息且根据呢称首字母进行排序分组,底部还统计了好友个数,右边是一组英文字母导航,可滑动并且还可以点击跳转到相应的分组

微信好友和顶部的四个标签,可以用listviw实现并指定一个item布局,分组效果只需要在代码段进行判断即可
右边的字母操作行可以自定义一个组件继承appcompattextview,为什么要用它呢,而不用textview呢?因为ui设计限定了一个文本的宽度,但是文本的长度可能比较长,如果设定一个固定的textsize,就导致一部分文本无法显示,而appcompattextview最显著的特点是可以自适应字体宽度大小变化。这个特点很有用,可以让文本随着文本宽度的变化,限定在一个固定范围内完整显示出来:
修改微信通信录界面的fragment布局
contactlist_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.wxchatdemo.mainweixin">
<listview
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@drawable/main_list_divider_line"
android:dividerheight="1.5px"
android:layout_marginbottom="50dp" />
<com.example.wxchatdemo.tools.sidebar
android:id="@+id/side_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignparentright="true"
android:layout_marginbottom="100dp"
android:layout_margintop="100dp"
android:paddingright="10dp"
android:textcolor="@color/black"
android:textsize="9sp" />
</relativelayout>
fragment整体布局使用相对布局,这样可以通过 android:layout_alignparentright="true"属性指定右边的自定义字母导航(sidebar继承appcompattextview)在父容器右边(即在屏幕中间的右边),相对布局包括两个组件(listview,sidebar)
创建自定义组件sidebar.java继承appcompattextview
sidebar.java
package com.example.wxchatdemo;
import android.content.context;
import android.content.res.typedarray;
import android.graphics.canvas;
import android.graphics.paint;
import android.util.attributeset;
import android.view.motionevent;
public class sidebar extends android.support.v7.widget.appcompattextview {
private string[] letters = new string[]{"a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l",
"m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
"w", "x", "y", "z", "#"};
private paint textpaint;
private paint bigtextpaint;
private paint scaletextpaint;
private canvas canvas;
private int itemh;
private int w;
private int h;
/**
* 普通情况下字体大小
*/
float singletexth;
/**
* 缩放离原始的宽度
*/
private float scalewidth;
/**
* 滑动的y
*/
private float eventy = 0;
/**
* 缩放的倍数
*/
private int scalesize = 1;
/**
* 缩放个数item,即开口大小
*/
private int scaleitemcount = 6;
private isidebarselectcallback callback;
public sidebar(context context) {
this(context, null);
}
public sidebar(context context, attributeset attrs) {
this(context, attrs, 0);
}
public sidebar(context context, attributeset attrs, int defstyleattr) {
super(context, attrs, defstyleattr);
init(attrs);
}
private void init(attributeset attrs) {
if (attrs != null) {
typedarray ta = getcontext().obtainstyledattributes(attrs, r.styleable.sidebar);
scalesize = ta.getinteger(r.styleable.sidebar_scalesize, 1);
scaleitemcount = ta.getinteger(r.styleable.sidebar_scaleitemcount, 6);
scalewidth = ta.getdimensionpixelsize(r.styleable.sidebar_scalewidth, dp(100));
ta.recycle();
}
textpaint = new paint(paint.anti_alias_flag);
textpaint.setcolor(getcurrenttextcolor());
textpaint.settextsize(gettextsize());
textpaint.settextalign(paint.align.center);
bigtextpaint = new paint(paint.anti_alias_flag);
bigtextpaint.setcolor(getcurrenttextcolor());
bigtextpaint.settextsize(gettextsize() * (scalesize + 3));
bigtextpaint.settextalign(paint.align.center);
scaletextpaint = new paint(paint.anti_alias_flag);
scaletextpaint.setcolor(getcurrenttextcolor());
scaletextpaint.settextsize(gettextsize() * (scalesize + 1));
scaletextpaint.settextalign(paint.align.center);
}
public void setdataresource(string[] data) {
letters = data;
invalidate();
}
public void setonstrselectcallback(isidebarselectcallback callback) {
this.callback = callback;
}
/**
* 设置字体缩放比例 * * @param scale
*/
public void setscalesize(int scale) {
scalesize = scale;
invalidate();
}
/**
* 设置缩放字体的个数,即开口大小 * * @param scaleitemcount
*/
public void setscaleitemcount(int scaleitemcount) {
this.scaleitemcount = scaleitemcount;
invalidate();
}
private int dp(int px) {
final float scale = getcontext().getresources().getdisplaymetrics().density;
return (int) (px * scale + 0.5f);
}
@override
public boolean ontouchevent(motionevent event) {
switch (event.getaction()) {
case motionevent.action_down:
case motionevent.action_move:
if (event.getx() > (w - getpaddingright() - singletexth - 10)) {
eventy = event.gety();
invalidate();
return true;
} else {
eventy = 0;
invalidate();
break;
}
case motionevent.action_cancel:
eventy = 0;
invalidate();
return true;
case motionevent.action_up:
if (event.getx() > (w - getpaddingright() - singletexth - 10)) {
eventy = 0;
invalidate();
return true;
} else
break;
}
return super.ontouchevent(event);
}
@override
protected void ondraw(canvas canvas) {
this.canvas = canvas;
drawview(eventy);
}
private void drawview(float y) {
int currentselectindex = -1;
if (y != 0) {
for (int i = 0; i < letters.length; i++) {
float currentitemy = itemh * i;
float nextitemy = itemh * (i + 1);
if (y >= currentitemy && y < nextitemy) {
currentselectindex = i;
if (callback != null) {
callback.onselectstr(currentselectindex, letters[i]);
} //画大的字母
paint.fontmetrics fontmetrics = bigtextpaint.getfontmetrics();
float bigtextsize = fontmetrics.descent - fontmetrics.ascent;
canvas.drawtext(letters[i], w - getpaddingright() - scalewidth - bigtextsize,
singletexth + itemh * i, bigtextpaint);
}
}
}
drawletters(y, currentselectindex);
}
private void drawletters(float y, int index) { //第一次进来没有缩放情况,默认画原图
if (index == -1) {
w = getmeasuredwidth();
h = getmeasuredheight();
itemh = h / letters.length;
paint.fontmetrics fontmetrics = textpaint.getfontmetrics();
singletexth = fontmetrics.descent - fontmetrics.ascent;
for (int i = 0; i < letters.length; i++) {
canvas.drawtext(letters[i], w - getpaddingright(), singletexth + itemh * i, textpaint);
} //触摸的时候画缩放图
} else { //遍历所有字母
for (int i = 0; i < letters.length; i++) { //要画的字母的起始y坐标
float currentitemtodrawy = singletexth + itemh * i;
float centeritemtodrawy;
if (index < i)
centeritemtodrawy = singletexth + itemh * (index + scaleitemcount);
else
centeritemtodrawy = singletexth + itemh * (index - scaleitemcount);
float delta = 1 - math.abs((y - currentitemtodrawy) / (centeritemtodrawy - currentitemtodrawy));
float maxrightx = w - getpaddingright(); //如果大于0,表明在y坐标上方
scaletextpaint.settextsize(gettextsize() + gettextsize() * delta);
float drawx = maxrightx - scalewidth * delta; //超出边界直接花在边界上
if (drawx > maxrightx)
canvas.drawtext(letters[i], maxrightx, singletexth + itemh * i, textpaint);
else
canvas.drawtext(letters[i], drawx, singletexth + itemh * i, scaletextpaint);
}
}
}
public interface isidebarselectcallback {
void onselectstr(int index, string selectstr);
}
}
右侧字母导航条,包括3个自定义的属性,下面将给出
在colors.xml文件添加如下代码
colors.xml
<declare-styleable name="sidebar">
<attr name="scalesize" format="integer"/>
<attr name="scaleitemcount" format="integer"/>
<attr name="scalewidth" format="dimension"/>
</declare-styleable>
要在字母导航中点击每一个字母可跳转相应分组,需要借助汉字转拼音工具类和自定义字母排序类,我们知道,java中是没有提供接口和方法让我们直接将汉字转成拼音的。在此我选择了使用第三方jar包的方式,因为它体积不大而且更加准确。
创建汉字转拼音工具类cn2spell.java
cn2spell.java
package com.example.wxchatdemo.tools;
import net.sourceforge.pinyin4j.pinyinhelper;
import net.sourceforge.pinyin4j.format.hanyupinyincasetype;
import net.sourceforge.pinyin4j.format.hanyupinyinoutputformat;
import net.sourceforge.pinyin4j.format.hanyupinyintonetype;
/** * 汉字转换位汉语拼音,英文字符不变 */
public class cn2spell {
public static stringbuffer sb = new stringbuffer();
/** * 获取汉字字符串的首字母,英文字符不变 * 例如:阿飞→af */
public static string getpinyinheadchar(string chines) {
sb.setlength(0);
char[] chars = chines.tochararray();
hanyupinyinoutputformat defaultformat = new hanyupinyinoutputformat();
defaultformat.setcasetype(hanyupinyincasetype.lowercase);
defaultformat.settonetype(hanyupinyintonetype.without_tone);
for (int i = 0; i < chars.length; i++) {
if (chars[i] > 128) {
try {
sb.append(pinyinhelper.tohanyupinyinstringarray(chars[i], defaultformat)[0].charat(0)); }
catch (exception e) {
e.printstacktrace(); }
}
else {
sb.append(chars[i]); }
}
return sb.tostring(); }
/** * 获取汉字字符串的第一个字母 */
public static string getpinyinfirstletter(string str) {
sb.setlength(0);
char c = str.charat(0);
string[] pinyinarray = pinyinhelper.tohanyupinyinstringarray(c);
if (pinyinarray != null) {
sb.append(pinyinarray[0].charat(0)); }
else {
sb.append(c);
}
return sb.tostring();
}
/** * 获取汉字字符串的汉语拼音,英文字符不变 */
public static string getpinyin(string chines) {
sb.setlength(0);
char[] namechar = chines.tochararray();
hanyupinyinoutputformat defaultformat = new hanyupinyinoutputformat();
defaultformat.setcasetype(hanyupinyincasetype.lowercase);
defaultformat.settonetype(hanyupinyintonetype.without_tone);
for (int i = 0; i < namechar.length; i++) {
if (namechar[i] > 128) {
try {
sb.append(pinyinhelper.tohanyupinyinstringarray(namechar[i], defaultformat)[0]);}
catch (exception e) {
e.printstacktrace(); }
}
else {
sb.append(namechar[i]); }
}
return sb.tostring();
}
}
把jar包导入项目libs库中,方法如下
在android studio中把项目结构改成project

此时目录就可以看到lib目录,把jar复制进去,然后添加到库中,方法和idea的是一样的,在以往文章中已经演示了

创建自定义字母排序类user.java
user.java
package com.example.wxchatdemo.tools;
public class user implements comparable<user> {
private string name; // 姓名
private string pinyin; // 姓名对应的拼音
private string firstletter; // 拼音的首字母
public user() { }
public user(string name) {
this.name = name;
pinyin = cn2spell.getpinyin(name); // 根据姓名获取拼音
firstletter = pinyin.substring(0, 1).touppercase(); // 获取拼音首字母并转成大写
if (!firstletter.matches("[a-z]")) { // 如果不在a-z中则默认为“#”
firstletter = "#"; }
}
public string getname() {
return name;
}
public string getpinyin() {
return pinyin;
}
public string getfirstletter() {
return firstletter;
}
@override
public int compareto(com.example.wxchatdemo.tools.user another) {
if (firstletter.equals("#") && !another.getfirstletter().equals("#")) {
return 1;
}
else if (!firstletter.equals("#") && another.getfirstletter().equals("#")){
return -1;
} else {
return pinyin.comparetoignorecase(another.getpinyin());
}
}
}
选择实现comparable接口,并重写comparato方法,原理很简单,就是先根据首字母判断,首字母为“#”都放在最后,都为“#”或者都是字母时才根据拼音来比较排序,让你的好友可以根据拼音来排序
修改通讯录fragment.java代码
contactlistfragment.java
上面代码主要内容就是先向服务器发送请求获取微信好友信息,初始化ui和数据,把数据封装再集合里并且实现滑动或选择字母索引时的回调接口,然后通过给listview设置自定义的适配器(后面会给出),并把数据集合一并传过去
既然用到了listview,我们就还需要一个适配器。
创建自定义适配器sortadapter.java
sortadapter.java
package com.example.wxchatdemo;
import android.annotation.suppresslint;
import android.app.fragment;
import android.os.bundle;
import android.os.handler;
import android.os.message;
import android.util.log;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.listview;
import com.example.wxchatdemo.adapter.sortadapter;
import com.example.wxchatdemo.tools.user;
import org.json.jsonobject;
import java.io.bufferedreader;
import java.io.bufferedwriter;
import java.io.inputstream;
import java.io.inputstreamreader;
import java.io.outputstream;
import java.io.outputstreamwriter;
import java.net.httpurlconnection;
import java.net.url;
import java.net.urlencoder;
import java.util.arraylist;
import java.util.collections;
import java.util.hashmap;
import java.util.list;
import java.util.map;
@suppresslint("validfragment")
public class contactlistfragment extends fragment {
string[] imgurl;
string[] name;
private string number; //微信号,通过微信号去查找通讯录
/* 声明组件*/
private listview listview;
private sidebar sidebar;
/*声明或创建集合,用于处理数据*/
private arraylist<user> list;
private arraylist<integer> list2;
private list<map<string, string>> data = new arraylist<map<string, string>>();
//自定义的一个hander消息机制
private myhander myhander = new myhander();
/*有参构造方法,参数为微信号*/
@suppresslint("validfragment")
contactlistfragment(string number) {
this.number = number;
}
public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) {
/*开启一个线程,用微信号向服务器请求通讯录数据*/
thread thread1 = new thread(new runnable() {
@override
public void run() {
httpurlconnpost(string.valueof(number));
}
});
thread1.start();
/*等待线性处理完成*/
try {
thread1.join();
} catch (interruptedexception e) {
e.printstacktrace();
}
//获取fragment布局
view view = inflater.inflate(r.layout.contactlist_fragment, container, false);
/*初始化组件*/
listview = (listview) view.findviewbyid(r.id.listview);
sidebar = (sidebar) view.findviewbyid(r.id.side_bar);
//初始化数据
initdata();
sidebar.setonstrselectcallback(new sidebar.isidebarselectcallback() {
@override
public void onselectstr(int index, string selectstr) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getname() == "新的朋友" || list.get(i).getname() == "群聊" ||
list.get(i).getname() == "标签" || list.get(i).getname() == "公众号" )
continue;
if (selectstr.equalsignorecase(list.get(i).getfirstletter())) {
listview.setselection(i); // 选择到首字母出现的位置
return;
}
}
}
});
return view;
}
private void initdata() {
//把从服务器获取解析的数据添加到map中,方便处理
map<string, string> map = new hashmap<string, string>();
for (int i = 0; i < imgurl.length; i ++) {
map.put(name[i], imgurl[i]);
}
data.add(map);
//名字要提取出来在添加到list中,因为要进行字母排序
list = new arraylist<>();
for (int i = 0; i < imgurl.length; i++) {
list.add(new user(name[i]));
}
collections.sort(list); // 对list进行排序,需要让user实现comparable接口重写compareto方法
//四个标签排序后再进行添加,好进行条件判断分离出来
list.add(0,new user("新的朋友"));
list.add(1,new user("群聊"));
list.add(2,new user("标签"));
list.add(3,new user("公众号"));
//四个标签图片不需要再服务器获取,直接移动端实现即可
list2 = new arraylist<>();
list2.add(r.drawable.newfriend);
list2.add(r.drawable.groupchat);
list2.add(r.drawable.sign);
list2.add(r.drawable.publicnum);
/*创建自定义适配器,并设置给listview*/
sortadapter adapter = new sortadapter(getactivity().getapplicationcontext(), list, list2, data);
listview.setadapter(adapter);
}
// 1.编写一个发送请求的方法
// 发送请求的主要方法
public void httpurlconnpost(string number) {
httpurlconnection urlconnection = null;
url url;
try {
// 请求的url地地址
url = new url(
"http://100.2.178.10:8080/androidserver_war_exploded/contact");
urlconnection = (httpurlconnection) url.openconnection();// 打开http连接
urlconnection.setconnecttimeout(3000);// 连接的超时时间
urlconnection.setusecaches(false);// 不使用缓存
// urlconnection.setfollowredirects(false);是static函数,作用于所有的urlconnection对象。
urlconnection.setinstancefollowredirects(true);// 是成员函数,仅作用于当前函数,设置这个连接是否可以被重定向
urlconnection.setreadtimeout(3000);// 响应的超时时间
urlconnection.setdoinput(true);// 设置这个连接是否可以写入数据
urlconnection.setdooutput(true);// 设置这个连接是否可以输出数据
urlconnection.setrequestmethod("post");// 设置请求的方式
urlconnection.setrequestproperty("content-type",
"application/json;charset=utf-8");// 设置消息的类型
urlconnection.connect();// 连接,从上述至此的配置必须要在connect之前完成,实际上它只是建立了一个与服务器的tcp连接
jsonobject json = new jsonobject();// 创建json对象
//json.put("title", urlencoder.encode(title, "utf-8"));// 使用urlencoder.encode对特殊和不可见字符进行编码
json.put("number", urlencoder.encode(number, "utf-8"));// 把数据put进json对象中
string jsonstr = json.tostring();// 把json对象按json的编码格式转换为字符串
// ------------字符流写入数据------------
outputstream out = urlconnection.getoutputstream();// 输出流,用来发送请求,http请求实际上直到这个函数里面才正式发送出去
bufferedwriter bw = new bufferedwriter(new outputstreamwriter(out));// 创建字符流对象并用高效缓冲流包装它,便获得最高的效率,发送的是字符串推荐用字符流,其它数据就用字节流
bw.write(jsonstr);// 把json字符串写入缓冲区中
bw.flush();// 刷新缓冲区,把数据发送出去,这步很重要
out.close();
bw.close();// 使用完关闭
log.i("aa", urlconnection.getresponsecode()+"");
//以下判斷是否訪問成功,如果返回的状态码是200则说明访问成功
if (urlconnection.getresponsecode() == httpurlconnection.http_ok) {// 得到服务端的返回码是否连接成功
// ------------字符流读取服务端返回的数据------------
inputstream in = urlconnection.getinputstream();
bufferedreader br = new bufferedreader(
new inputstreamreader(in));
string str = null;
stringbuffer buffer = new stringbuffer();
while ((str = br.readline()) != null) {// bufferedreader特有功能,一次读取一行数据
system.out.println("测试:" + str);
buffer.append(str);
}
in.close();
br.close();
jsonobject rjson = new jsonobject(buffer.tostring());
string str1 = rjson.getjsonobject("json").get("img").tostring();
imgurl = str1.split("\r\n");
string str2 = rjson.getjsonobject("json").get("name").tostring();
name = str2.split("\r\n");
boolean result = rjson.getboolean("json");// 从rjson对象中得到key值为"json"的数据,这里服务端返回的是一个boolean类型的数据
system.out.println("json:===" + result);
//如果服务器端返回的是true,则说明注册成功,否则注册失败
if (result) {// 判断结果是否正确
//在android中http请求,必须放到线程中去作请求,但是在线程中不可以直接修改ui,只能通过hander机制来完成对ui的操作
myhander.sendemptymessage(1);
log.i("用户:", "登录成功");
} else {
myhander.sendemptymessage(2);
system.out.println("222222222222222");
log.i("用户:", "登录失败");
}
} else {
myhander.sendemptymessage(2);
}
} catch (exception e) {
e.printstacktrace();
log.i("aa", e.tostring());
system.out.println("11111111111111111");
myhander.sendemptymessage(2);
} finally {
urlconnection.disconnect();// 使用完关闭tcp连接,释放资源
}
}
// 在android中不可以在线程中直接修改ui,只能借助handler机制来完成对ui的操作
class myhander extends handler {
@override
public void handlemessage(message msg) {
super.handlemessage(msg);
//判断hander的内容是什么,如果是1则说明注册成功,如果是2说明注册失败
switch (msg.what) {
case 1:
log.i("aa", msg.what + "");
break;
case 2:
log.i("aa", msg.what + "");
}
}
}
}
上面代码主要功能就是把数据呈现再相应组件上
适配器还用到了一个布局,即listview对应布局,创建contactlist_item.xml
contactlist_item.xml
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
<textview
android:id="@+id/catalog"
android:layout_width="match_parent"
android:layout_height="32dp"
android:background="#e0e0e0"
android:paddingleft="10dp"
android:paddingtop="5dp"
android:textcolor="#454545"
android:textsize="13sp" />
<linearlayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<imageview
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="10dp" />
<textview
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:padding="10dp"
android:textcolor="#336598"
android:textsize="16sp" />
</linearlayout>
<view
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#90909090" />
<textview
android:id="@+id/contact_count"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#ffffff"
android:paddingleft="150dp"
android:paddingtop="5dp"
android:textcolor="#454545"
android:textsize="13sp" />
</linearlayout>
布局有四部分,第一个是目录,即a,b,c,d这样的索引,仅当该目录下的第一项出现时才显示;第二个是线性布局,里面包括微信头像和姓名,第三个是自定义的分割线性(通过view实现),因为微信最后一个联系人的分割线是宽度充满屏幕的,要单独定义,最后一个是统计联系人的textview组件
服务端微信通讯录界面功能实现
服务端的功能和以往文章是类似,就不详细demo了,直接上代码
创建servlet contact.java,实现服务端和客户端的数据交互
contact.java
package com.example.controller;
import com.alibaba.fastjson.json;
import com.alibaba.fastjson.jsonobject;
import com.example.pojo.contactlist;
import com.example.service.userserviceimpl;
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 java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.net.urldecoder;
@webservlet(name = "contact", value = "/contact")
public class contact extends httpservlet {
@override
protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
dopost(request,response);
}
@override
protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
//设置字符编码,防止中文乱码
request.setcharacterencoding("utf-8");
response.setcharacterencoding("utf-8");
//以json数据完成操作
response.setcontenttype("application/json;charset=utf-8");
system.out.println(request.getcontenttype());// 得到客户端发送过来内容的类型,application/json;charset=utf-8
system.out.println(request.getremoteaddr());// 得到客户端的ip地址,
bufferedreader br = new bufferedreader(new inputstreamreader(// 使用字符流读取客户端发过来的数据
request.getinputstream()));
string line = null;
stringbuffer s = new stringbuffer();//stringbuffer string的区别,如果要对数据作頻繁的修改,則用stringbuffer
// 以一行的形式读取数据
while ((line = br.readline()) != null) {
s.append(line);
}
// 关闭io流
br.close();
system.out.println(s.tostring());// {"password":"123456","name":"admin"}
//json:这是json解析包,idea是没有,要我们自己导入
contactlist contactlist = json.parseobject(s.tostring(), contactlist.class);//是用了反射机制來完成对象的封闭
//以utf-8解码操作
string number = urldecoder.decode(contactlist.getnumber(), "utf-8");
system.out.println(contactlist);
// 去数据库完成用户登录功能
userserviceimpl us = new userserviceimpl();
//调用登录的方法
contactlist contactlist1 = us.contact(number);
if(contactlist1 != null) {
//将结果返回给客户端 ,將結果構建成json數據返回給客戶端
jsonobject rjson = new jsonobject();
rjson.put("json", contactlist1 );
response.getoutputstream().write(
rjson.tostring().getbytes("utf-8"));// 向客户端发送一个带有json对象内容的响应
}
}
}
上面代码用到微信通讯录界面的实体类,下面将给出
实体类contactlist.java
contactlist.java
package com.example.pojo;
public class contactlist {
private int id;
private string img;
private string name;
private string number;
public int getid() {
return id;
}
public void setid(int id) {
this.id = id;
}
public string getimg() {
return img;
}
public void setimg(string img) {
this.img = img;
}
public string getname() {
return name;
}
public void setname(string name) {
this.name = name;
}
public string getnumber() {
return number;
}
public void setnumber(string number) {
this.number = number;
}
@override
public string tostring() {
return "contactlist{" +
"id=" + id +
", img='" + img + '\'' +
", name='" + name + '\'' +
", number='" + number + '\'' +
'}';
}
}
在service层中的接口userservice.java添加处理微信通讯录界面数据业务逻辑处理的抽象方法
//微信通讯录
contactlist contact(string number);
在service层中的类userserviceimpl.java重写上面接口刚添加的方法
public contactlist contact(string number) {
//调用dao层完成数据查询操作
contactlist contactlist = ud.findcontact(number);
return contactlist;
}
在dao层中的接口userdao .java添加处理微信通信录界面数据并操作数据库的的抽象方法
//查询微信通信录列表
contactlist findcontact(string number);
在dao层中的类userdaoimpl.java重写上面接口刚添加的方法
@override
public contactlist findcontact(string number) {
string sql = "select * from contact where number=?;";
resultset rs = jdbcutil.executequery(sql, number);
//判断是否查询到用户
try {
if (rs.next()) {
//如果查询到用户,将用户封装到user对象中
int id = rs.getint("id");
string img = rs.getstring("img");
string name = rs.getstring("name");
string number1 = rs.getstring("number");
//将查询到的用户封装到一个user对象中
contactlist contactlist = new contactlist();
contactlist .setid(id);
contactlist .setimg(img);
contactlist .setname(name);
contactlist .setnumber(number1);
system.out.println("查询到的用户" + contactlist);
return contactlist;
}
}catch (sqlexception throwables) {
throwables.printstacktrace();
}
return null;
}
在imgs目录下创建存放通讯录微信头像的目录,之后再往里添加图片即可

下面给出我的表结构以及表内容


每一条记录对应一个用户,客户端通过微信号向服务器发送请求,服务器接受请求后向数据库进行查找,如果查找成功将返回一条记录给服务端,客户端进行解析分离
测试
测试前要事先在数据库里添加数据

总结
这篇关于微信demo的文章就到这里了,希望大家可以多多关注的更多精彩内容!
亖呉?盀