当前位置: 首页 > 编程日记 > 正文

Android_开源框架_Volley实例

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1.自定义相关类

在 Android_开源框架_Volley(Google IO 2013)源代码及内部实现过程分析一文中,简单概述了Volley框架内部实现过程。如想理解彻底应该熟悉 android多线程通信机制( Android_Thread多线程_Handler,Message,Looper,MessageQueue多线程和特殊UI更新一文) ,JDK1.5提供的 java.util.concurrent相关并发库和 http访问网络( Android_HttpURLConnection_Get和Post请求[该框架使用] / Android_HttpClient_get请求post表单提交上传 一文)及 图片缓存( Android_图片的三级缓存一文)相关知识

  1. https://android.googlesource.com/platform/frameworks/volley
复制代码

(1).封装MyVolley类
在使用Volley之前,应该先进行初始化(可以自定义Application或者在SplashActivity中完成初始化),仅对外提供RequestQueue(添加request)和ImageLoader(下载图片)get方法!

  1. /**
  2. * MyVolley.java
  3. * @author zimo2013
  4. * [url=home.php?mod=space&uid=189949]@See[/url] http://blog.csdn.net/zimo2013
  5. *
  6. */
  7. public class MyVolley {
  8. private static final String TAG = "MyVolley";

  9. private static MyVolley instance;
  10. private static RequestQueue mRequestQueue;
  11. private static ImageLoader mImageLoader;
  12. private final static int RATE = 8; // 默认分配最大空间的几分之一

  13. private MyVolley(Context context) {
  14. mRequestQueue = Volley.newRequestQueue(context);

  15. // 确定在LruCache中,分配缓存空间大小,默认程序分配最大空间的 1/8
  16. ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
  17. int maxSize = manager.getMemoryClass() / RATE; // 比如 64M/8,单位为M

  18. //BitmapLruCache自定义缓存class,该框架本身支持二级缓存,在BitmapLruCache封装一个软引用缓存
  19. mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache(1024*1024*maxSize));

  20. LogUtil.i(TAG, "MyVolley初始化完成");
  21. }

  22. /**
  23. * 初始化Volley相关对象,在使用Volley前应该完成初始化
  24. *
  25. * @param context
  26. */
  27. public static void init(Context context) {
  28. if (instance == null) {
  29. instance = new MyVolley(context);
  30. } else {
  31. LogUtil.w(TAG, "已经初始化过,不需要再次调用init()");
  32. }
  33. }

  34. /**
  35. * 得到请求队列对象
  36. *
  37. * @return
  38. */
  39. public static RequestQueue getRequestQueue() {
  40. throwIfNotInit();
  41. return mRequestQueue;
  42. }

  43. /**
  44. * 得到ImageLoader对象
  45. *
  46. * @return
  47. */
  48. public static ImageLoader getImageLoader() {
  49. throwIfNotInit();
  50. return mImageLoader;
  51. }

  52. /**
  53. * 检查是否完成初始化
  54. */
  55. private static void throwIfNotInit() {
  56. if (instance == null) {// 尚未初始化
  57. throw new IllegalStateException("MyVolley尚未初始化,在使用前应该执行init()");
  58. }
  59. }
  60. }
复制代码

(2).图片的三级缓存相关类
  1. /**
  2. * LruCache缓存管理类,该类实现了ImageCache接口,并实现了LruCache
  3. * 一旦bitmap对象从LruCache中被挤出,将会被放置在BitmapSoftRefCache中,再配合该框架本身支持的硬盘缓存,可以完成图片三级缓存
  4. *
  5. * BitmapLruCache.java
  6. * @author zimo2013
  7. * @see http://blog.csdn.net/zimo2013
  8. *
  9. */
  10. public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache {
  11. private static final String TAG = "BitmapLruCache";

  12. private BitmapSoftRefCache softRefCache;

  13. public BitmapLruCache(int maxSize) {
  14. super(maxSize);
  15. softRefCache = new BitmapSoftRefCache();
  16. }

  17. @Override
  18. protected int sizeOf(String key, Bitmap value) {
  19. return value.getRowBytes() * value.getHeight();
  20. }

  21. @Override
  22. protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
  23. if (evicted) {
  24. LogUtil.i(TAG, "空间已满,缓存图片被挤出:" + key);
  25. // 将被挤出的bitmap对象,添加至软引用BitmapSoftRefCache
  26. softRefCache.putBitmap(key, oldValue);
  27. }
  28. }

  29. /**
  30. * 得到缓存对象
  31. */
  32. @Override
  33. public Bitmap getBitmap(String url) {
  34. Bitmap bitmap = get(url);
  35. // 如果bitmap为null,尝试从软引用缓存中查找
  36. if (bitmap == null) {
  37. bitmap = softRefCache.getBitmap(url);
  38. } else {
  39. LogUtil.i(TAG, "LruCache命中:" + url);
  40. }
  41. return bitmap;
  42. }

  43. /**
  44. * 添加缓存对象
  45. */
  46. @Override
  47. public void putBitmap(String url, Bitmap bitmap) {
  48. put(url, bitmap);
  49. }

  50. }
复制代码
  1. /**
  2. * 软引用缓存管理类
  3. *
  4. * BitmapSoftRefCache.java
  5. * @author zimo2013
  6. * @see http://blog.csdn.net/zimo2013
  7. *
  8. */
  9. public class BitmapSoftRefCache implements ImageCache{
  10. private static final String TAG = "BitmapSoftRefCache";

  11. private LinkedHashMap<String, SoftReference<Bitmap>> map;
  12. public BitmapSoftRefCache() {
  13. map = new LinkedHashMap<String, SoftReference<Bitmap>>();
  14. }

  15. /**
  16. * 从软引用集合中得到Bitmap对象
  17. */
  18. @Override
  19. public Bitmap getBitmap(String url) {
  20. Bitmap bitmap = null;
  21. SoftReference<Bitmap> softRef = map.get(url);
  22. if(softRef != null){
  23. bitmap = softRef.get();
  24. if(bitmap == null){
  25. map.remove(url); //从map中移除
  26. LogUtil.w(TAG, url+"对象已经被GC回收");
  27. }else{
  28. LogUtil.i(TAG, "命中"+url);
  29. }
  30. }
  31. return bitmap;
  32. }

  33. /**
  34. * 从软引用集合中添加bitmap对象
  35. */
  36. @Override
  37. public void putBitmap(String url, Bitmap bitmap) {
  38. SoftReference<Bitmap> softRef = new SoftReference<Bitmap>(bitmap);
  39. map.put(url, softRef);
  40. }

  41. }
复制代码

(3).图片错位
关于使用该框架造成图片错位问题,App使用了ImageLoader下载图片,当ListView滚动很快时,还是会发生错位!记得听别人提起过,使用该框架可以避免图片错位,但是结果还是会发生错位,查看源码并没有找到相关避免错位的措施,不知道是不是自己的使用方法不对,如您知晓,麻烦告知博主一下~这里通过覆写ImageListener方法,通过ImageView为其指定Tag标签,防止图片错位,即比对 下载完图片的ImageUrl和当前该 ImageView的Tag是否相等~
  1. public class ImageListenerFactory{

  2. public static ImageListener getImageListener(final ImageView view,
  3. final int defaultImageResId, final int errorImageResId) {
  4. return new ImageListener() {
  5. @Override
  6. public void onErrorResponse(VolleyError error) {
  7. if (errorImageResId != 0) {
  8. view.setImageResource(errorImageResId);
  9. }
  10. }

  11. @Override
  12. public void onResponse(ImageContainer response, boolean isImmediate) {
  13. if (response.getBitmap() != null) {

  14. if(view.getTag().toString() == response.getRequestUrl()){
  15. view.setImageBitmap(response.getBitmap());
  16. }else{
  17. LogUtil.i(TAG, "图片错位");
  18. }
  19. } else if (defaultImageResId != 0) {
  20. view.setImageResource(defaultImageResId);
  21. }
  22. }
  23. };
  24. }
  25. }
复制代码

2.网络请求Request
(1).StringRequest
  1. public void testStringRequest(){
  2. String url = "http://www.baidu.com";
  3. //如果出现乱码,应该修改StringRequest的parseNetworkResponse()方法,指定byte[]-->String 编码
  4. MyVolley.getRequestQueue().add(new StringRequest(url, new Response.Listener<String>() {

  5. @Override
  6. public void onResponse(String response) {
  7. System.out.println("response:"+response);
  8. }
  9. }, new Response.ErrorListener() {

  10. @Override
  11. public void onErrorResponse(VolleyError error) {

  12. }
  13. }));
  14. }
复制代码

(2).JsonObjectRequest
  1. public void testJsonObjectRequest(){
  2. String url = "http://api.mobile.meituan.com/group/v1/deal/new-cate-list/android/4.1?cityId=1";
  3. //如果出现乱码,应该修改StringRequest的parseNetworkResponse()方法,指定byte[]-->String 编码
  4. MyVolley.getRequestQueue().add(
  5. new JsonObjectRequest(url,
  6. null,
  7. new Response.Listener<JSONObject>() {

  8. @Override
  9. public void onResponse(JSONObject response) {
  10. //该JSONObject为android系统提供的,如果希望得到一个已经解析完的对象,可以继承JsonRequest

  11. //根据response,解析数据
  12. try {
  13. System.out.println(response.get("stid"));
  14. } catch (JSONException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. },new Response.ErrorListener() {

  19. @Override
  20. public void onErrorResponse(VolleyError error) {
  21. System.out.println(error);
  22. }
  23. })
  24. );
  25. }
复制代码

(3).自定义Request(Json解析)
  1. /**
  2. * MyJsonRequest.java
  3. *
  4. * @author zimo2013
  5. * @see http://blog.csdn.net/zimo2013
  6. */
  7. public class MyJsonRequest<T> extends JsonRequest<T> {
  8. private Gson gson;
  9. private Class<T> clazz;

  10. /**
  11. * 默认为GET请求方式
  12. * @param url
  13. * @param clazz                解析的class字节码
  14. * @param listener 请求成功监听器
  15. * @param errorListener        请求失败监听器
  16. */
  17. public MyJsonRequest(String url, Class<T> clazz, Listener<T> listener,
  18. ErrorListener errorListener) {
  19. this(Method.GET, url, null, clazz, listener, errorListener);
  20. }

  21. /**
  22. *
  23. * @param method        请求方法 Use {@link com.android.volley.Request.Method}.
  24. * @param url
  25. * @param requestBody        如果是POST请求,可以提交form表单字符串,比如 name=zhangsan&age=20
  26. * @param clazz                解析的class字节码
  27. * @param listener 请求成功监听器
  28. * @param errorListener        请求失败监听器
  29. */
  30. public MyJsonRequest(int method, String url, String requestBody, Class<T> clazz,
  31. Listener<T> listener, ErrorListener errorListener) {
  32. super(method, url, null, listener, errorListener);

  33. this.clazz = clazz;
  34. gson = new Gson();
  35. }

  36. @Override
  37. protected Response<T> parseNetworkResponse(NetworkResponse response) {
  38. try {
  39. String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
  40. return Response.success(gson.fromJson(json, clazz),
  41. HttpHeaderParser.parseCacheHeaders(response));
  42. } catch (UnsupportedEncodingException e) {
  43. return Response.error(new ParseError(e));
  44. } catch (JsonSyntaxException e) {
  45. return Response.error(new ParseError(e));
  46. }
  47. }
  48. }
复制代码
  1. public void testCustomRequest(){
  2. String urlString = "http://192.168.117.120:8080/news/json.html";
  3. MyJsonRequest<NewsInfo> request = new MyJsonRequest<NewsInfo>(urlString, NewsInfo.class, new Listener<NewsInfo>() {

  4. @Override
  5. public void onResponse(NewsInfo response) {
  6. System.out.println(response.getClass());
  7. System.out.println(response);
  8. }
  9. }, null);
  10. MyVolley.getRequestQueue().add(request);
  11. }
复制代码

(4).POST表单提交
  1. public void testRequestByPost(){
  2. String urlString = "http://192.168.43.240:8080/news/servlet/Post";
  3. StringRequest request = new StringRequest(Method.POST, urlString, new Listener<String>() {

  4. @Override
  5. public void onResponse(String response) {

  6. }
  7. }, new ErrorListener() {

  8. @Override
  9. public void onErrorResponse(VolleyError error) {

  10. }
  11. }){
  12. //覆写getBody()方法提交表单数据
  13. @Override
  14. public byte[] getBody() {
  15. return "name=zhangsan&age=15".getBytes();
  16. }
  17. };
  18. MyVolley.getRequestQueue().add(request);
  19. }
复制代码

(5).ImageLoader异步加载图片(防错位)
  1. public void testImageLoader(){
  2. MyVolley.getImageLoader().get(imgUrl,
  3. //ImageListenerFactory为自定义类,封装后即可获取图片资源,完成UI更新
  4. ImageListenerFactory.getImageListener(//参考ImageLoader.getImageListener()
  5. imageView,                 // ImageView对象
  6. R.drawable.ic_launcher, // 默认Image,如果不设应置为0
  7. R.drawable.ic_launcher)); // 错误Image,如果不设应置为0
  8. }

转载于:https://my.oschina.net/u/1420982/blog/184210

相关文章:

maven的配置-2019-4-13

一.Maven的优点 1. 依赖管理 jar 包管理 2.一键构建 &#xff08;编译-----测试------打包-----安装-----部署 &#xff09; 什么是项目构建&#xff1f; 指的是项目从编译-----测试------打包-----安装-----部署 整个过程都交给maven进行管理&#xff0c;这个过程称为构建 一…

WiredTiger引擎编译 及 LT_PREREQ(2.2.6)问题解决

近期需要为异构引擎做准备&#xff0c; wiredtiger 以其优异的性能(B-tree和LSM-tree都支持)和稳定性(Mongodb的默认存储引擎) 被我们备选为异构引擎里的一个子引擎&#xff0c;后续将深入wiredtiger 引擎原理。这里简单记录一下Wiredtiger 存储引擎的编译记录。 Environment …

Java项目:员工管理系统(前后端分离+java+vue+Springboot+ssm+mysql+maven+redis)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 本系统功能包括&#xff1a;分为前端翻后端部分&#xff0c;包括用户&#xff0c;区分晋通用户以及誉里员用户&#xff0c;包括首页展示&#xff0c;部门管理&#xff0c;人事管理&#xff0c…

缺陷重点内容分析

1.缺陷优先级 序号优先级描述1低暂时不影响继续测试&#xff0c;可以在方便时解决2中部分功能测试无法继续测试&#xff1b;需要优先解决3高测试暂停&#xff0c;无法进行&#xff0c;必须立即解决2.缺陷的状态&#xff08;图片来自云测视频&#xff09; 3.缺陷生命周期与管理流…

关于node.js的误会

昨天写了篇博客&#xff0c;介绍了一下我对node.js的第一次亲密接触后的感受&#xff0c;以为node.js很小众&#xff0c;出乎我意料很多人感兴趣&#xff0c;并且对博客中的细节问题做了评论&#xff0c;最多的是围绕node.js的异步与单线程展开的&#xff0c;当然还有很多关于n…

文本相关CSS

文本相关CSS 属性 word-breakoverflow-wrap(word-wrap)white-spacetext-overflowtext-wrap(目前主流浏览器都不支持)应用 一般断行需求实现文本不换行&#xff0c;以省略号表示超出的部分参考资料属性 word-break 作用&#xff1a;指定非CJK(中日韩)文本的断行规则。&#xff0…

Rocksdb 的优秀代码(三)-- 工业级 线程池实现分享

文章目录前言1. Rocksdb线程池概览2. Rocksdb 线程池实现2.1 基本数据结构2.2 线程池创建2.3 线程池 调度线程执行2.4 线程池销毁线程2.5 线程池优先级调度2.6 动态调整线程池 线程数目上限3. 总结前言 Rocksdb 作为一个第三方库的形态嵌入到各个存储系统之中存储元数据&#…

Java项目:网上电商项目(前后端分离+java+vue+Springboot+ssm+mysql+maven+redis)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 本系统功能包括&#xff1a; 一款基于SpringbootVue的电商项目&#xff0c;前后端分离项目&#xff0c;前台后台都有&#xff0c;前台商品展示购买&#xff0c;购物车分类&#xff0c;订 单查…

3月7日 ArrayList集合

ArrayList与数组的区别&#xff1a; 数组是连续的、同一类型数据的一块区域&#xff0c;而集合可以是不连续的、多种数据类型的。 1.ArrayList ArrayList al new ArrayList(); al.Add(3); al.Add(5.09); al.Add("gfdg"); al.Inse…

什么时候出生好?

从年龄来说&#xff0c;女人头一胎的怀孕时间最好在35岁以前&#xff0c;因为过了35岁后不孕和头胎生育缺陷的比例会大幅度升高。那么&#xff0c;从孩子的角度&#xff0c;什么时候出生好&#xff1f;很多人不考虑这个问题&#xff0c;能不能怀上还难说那。迷信的人则追求出生…

数据库搜索与索引

索引是对数据库表中一列或多列的值进行排序的一种结构&#xff0c;使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她&#xff0c;则与在表中搜索所有的行相比&#xff0c;索引有助于更快地获取信息。 索引的一个主要目的就是加快检索表中数据&#x…

Clion 远程开发 配置

文章目录1. 增加远端服务工具2. 配置远端服务器3. 配置编译选项4. 设置远端开发路径Clion作为C/C语言友好的IDE&#xff0c;除了高效的代码索引 以及 基本的本地开发 能力之外还需要有远程开发能力&#xff0c;即我们工作中的代码处于远端linux服务器之上&#xff0c;通过在本地…

Java项目:朴素风个人博客系统(前后端分离+java+vue+Springboot+ssm+mysql+maven+redis)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 本系统功能包括&#xff1a; 基于vue Springboo痼J后端分离项目个人博客系统&#xff0c;注册 登录&#xff0c;首页展示&#xff0c;喜爰图书展示&#xff0c;后台图书维护&#xff0c;个人…

NodeJS+Mongodb+Express做CMS博客系统

楼主正在用业余时间开发中…… &#xff0c;目前的版本仅支持会员系统&#xff0c;尝鲜一下吧~ hi-blog 一个 nodejsexpressmongodb 的 cms 系统怎么启动 默认你已经安装了 mongodb &#xff1b;那么你得这样操作&#xff1a;安装项目 -> 初始化管理员 -> 运行项目 1、请…

Piranha实验总结

操作系统&#xff1a;rhel5.8分别在DirectorMaster和DirectorBackup上部署浮动资源(VIP IPVS策略)测试2个Director在DR模式下是否都可以正常工作。测试完成后都撤掉浮动资源。DirectorMaster[rootlocalhost ~]#yum install piranha[rootlocalhost ~]#piranha-passwdNew Passwor…

虚IP切换原理

高可用性HA&#xff08;High Availability&#xff09;指的是通过尽量缩短因日常维护操作&#xff08;计划&#xff09;和突发的系统崩溃&#xff08;非计划&#xff09;所导致的停机时间&#xff0c;以提高系统和应用的可用性。HA系统是目前企业防止核心计算机系统因故障停机的…

vim 键盘宏操作 -- 大道至简

最近利用vim做一些文本处理时 发现vim 支持的键盘宏是一个好东西啊&#xff0c;高效优雅得处理大量需要重复性操作的文本&#xff0c;让人爱不释手&#xff01;&#xff01;&#xff01; 希望接下来对键盘宏的分享能够实际帮助到大家。 后文中描述的一些vim操作会汇集成指令字…

Java项目:家居购物商城系统(java+html+jdbc+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a; Java Web精品项目源码&#xff0c;家居商城分类展示&#xff0c;商品展示&#xff0c; 商品下单&#xff0c;购物车&#xff0c;个人中心&#xff0c;后台管理&#xff0c;用…

leetcode:Search in Rotated Sorted Array

题目要求&#xff1a; Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). You are given a target value to search. If found in the array return its index, otherwise return -1. You may a…

解决Debian-7.1下Chrome浏览器字体难看的问题

首先在 Advance Setting 的 font 标签页下做如下配置&#xff1a; 然后在用户目录下创建 .fonts.conf 文件&#xff0c;内容如下&#xff1a; <?xml version1.0?> <!DOCTYPE fontconfig SYSTEM fonts.dtd> <fontconfig><match target"font"&g…

HDU.4903.The only survival(组合 计数)

题目链接 惊了 \(Description\) 给定\(n,k,L\)&#xff0c;表示&#xff0c;有一张\(n\)个点的无向完全图&#xff0c;每条边的边权在\([1,L]\)之间。求有多少张无向完全图满足&#xff0c;\(1\)到\(n\)的最短路为\(k\)。\(n,k\leq 12,\ L\leq10^9\)。 \(Solution\) 考虑暴力&a…

Rocksdb 写入数据后 GetApproximateSizes 获取的大小竟然为0?

项目开发中需要从引擎 获取一定范围的数据大小&#xff0c;用作打点上报&#xff0c;测试过程中竟然发现写入了一部分数据之后通过GetApproximateSizes 获取写入的key的范围时取出来的数据大小竟然为0。。。难道发现了一个bug?&#xff08;欣喜&#xff09; 因为写入的数据是…

Java项目:在线婚纱摄影预定系统(java+javaweb+SSM+springboot+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a; 前后用户的登录注册&#xff0c;婚纱照片分类&#xff0c;查看&#xff0c;摄影师预 订&#xff0c;后台订单管理&#xff0c;图片管理等等。 二、项目运行 环境配置&am…

Linux Terminal 控制终端的使用

1. Open new Terminal&#xff1a;Ctrl Alt T 或者 Ctrl Shift N 2. Open Tab&#xff1a;Ctrl Shift T 3. Close Tab&#xff1a;Ctrl Shift W 4. Close Window&#xff1a;Ctrl Shift Q 5. Copy : Ctrl Shift C 6. Paste: Ctrl Shift V 7. Full Screen: F11 8.…

如何防止代码腐烂

http://blog.jobbole.com/5643/ 很多团队都有这个问题&#xff0c;一个项目的代码本来开始设计得好好的&#xff0c;一段时间以后&#xff0c;代码就会变得难以理解&#xff0c;难以维护&#xff0c;难以修改。为什么&#xff1f;我一直在思考这个问题。 让我们先看一个人的情况…

CORS在Spring中的实现

CORS: 通常情况下浏览器禁止AJAX从外部获取资源&#xff0c;因此就衍生了CORS这一标准体系&#xff0c;来实现跨域请求。 CORS是一个W3C标准&#xff0c;全称是"跨域资源共享"&#xff08;Cross-origin resource sharing&#xff09;。它允许浏览器向跨源(协议 域名…

从BloomFilter到Counter BloomFilter

文章目录前言1. Traditional BloomFilter2. Counter BloomFilter本文traditional bloomfilter 和 counter bloomfilter的C实现 均已上传至&#xff1a; https://github.com/BaronStack/BloomFilter 前言 Bloomfilter 是一个老生常谈的数据结构&#xff0c;应用在存储领域的各…

进程、线程、多线程相关总结

进程、线程、多线程相关总结 一、说说概念 1、进程&#xff08;process&#xff09; 狭义定义&#xff1a;进程就是一段程序的执行过程。 广义定义&#xff1a;进程是一个程序关于某个数据集合的一次运行。它是操作系统动态执行的基本单元&#xff0c;在传统的操作系统中&#…

Java项目:在线蛋糕商城系统(java+jsp+jdbc+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a; 主页显示热销商品&#xff1b;所有蛋糕商品展示&#xff0c;可进行商品搜 索&#xff1b;点击商品进入商品详情页&#xff0c;具有立即购买和加入购物 车功能&#xff0c;可…

业界对生成图片缩略图的做法归纳

网站如果有很多用户上传图片(相册&#xff0c;商品图片)&#xff0c;一般的做法是将用户图片保存在磁盘上面(数据库中记录图片的地址)。用户上传的时候按照原图、中图、小图等各个尺寸都生成一份保存在磁盘上。比如php的网店系统echsop就是这么做的&#xff0c;而shopex之类也大…