经典的数据库访问接口-程序员宅基地

技术标签: java  编程学习  数据库  

package org.lyq.dao;

import java.io.IOException;
import java.io.InputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
/** 
 * 经典的数据库访问接口 
 * @author 李永强 
 * @version 2.0 
 */
public class DBUtil {
 private static DBUtil dbUtil = null;  
    private List<Connection> idle = new ArrayList<Connection>(0);  
    private Map<Thread, Connection> busy = new HashMap<Thread, Connection>(0);  
    private Map<String, Connection> cache = new HashMap<String, Connection>(0);  
    private String dialect = "ORACLE";  
    private int maxsize = 3;  
 
    /** 
     * 私有构造不让直接创建一个DBUtil实例 读取配置文件加载数据库配置信息,创建一定数量的连接到连接池
     */ 
    private DBUtil() {  
        InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("db_cfg.properties");  
        Properties prop = new Properties();  
        try {  
            prop.load(in);  
            String driver = (String) prop.get("db.driver");  
            String url = (String) prop.get("db.url");  
            String username = (String) prop.get("db.username");  
            String password = (String) prop.get("db.password");  
            if (prop.get("db.maxsize") != null) {  
                maxsize = Integer.parseInt(prop.get("db.maxsize").toString());  
            }  
            if (prop.get("db.dialect") != null) {  
                dialect = (String) prop.get("db.dialect");  
            }  
            Class.forName(driver);  
            for (int k = 0; k < maxsize; k++) {  
                Connection conn = DriverManager.getConnection(url, username, password);  
                idle.add(conn);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            try {  
                in.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
 
    /** 
     * 获得数据库访问接口 
     * @return 数据库访问接口DBUtil单例 
     */ 
    public static DBUtil getInstance() {  
        if (null == dbUtil) {  
            dbUtil = new DBUtil();  
        }  
        return dbUtil;  
    }  
 
    /** 
     * 获得数据库连接 
     * @return 数据库连接 
     */ 
    private synchronized Connection getConn() {  
        Connection conn = null;  
        try {  
            if (idle.size() == 0) {  
                wait();  
            }  
            conn = idle.get(0);  
            busy.put(Thread.currentThread(), conn);  
            idle.remove(0);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return conn;  
    }  
 
    /** 
     * 关闭所有对对象,归还链接到连接池 
     * @param rs  数据集对象 
     * @param ps 命令对象 
     */ 
    private synchronized void closeAll(ResultSet rs, PreparedStatement ps) {  
        if (null != rs) {  
            try {  
                rs.close();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
        }  
        if (null != ps) {  
            try {  
                ps.close();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
        }  
        Connection conn = busy.get(Thread.currentThread());  
        if (null != conn) {  
            idle.add(conn);  
            busy.remove(Thread.currentThread());  
            notify();  
        }  
    }  
 
    /** 
     * 无事务更新(不带参数) 
     * @param sql  SQL语句 :"update table set price=200.00" 
     * @return 受影响行数 
     * @throws SQLException 
     */ 
    public int update(String sql) throws SQLException {  
        int result = 0;  
        Connection conn = null;  
        PreparedStatement ps = null;  
        try {  
            conn = getConn();  
            ps = conn.prepareStatement(sql);  
            result = ps.executeUpdate();  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(null, ps);  
        }  
        return result;  
    }  
 
    /** 
     * 无事务更新(带参数) 
     * @param sql SQL语句 :"delete from table where id=?" 
     * @param params  参数对象数组 :new Object[]{参数1,参数2,...} 
     * @return 受影响行数 
     * @throws SQLException 
     */ 
    public int update(String sql, Object[] params) throws SQLException {  
        int result = 0;  
        Connection conn = null;  
        PreparedStatement ps = null;  
        try {  
            conn = getConn();  
            ps = conn.prepareStatement(sql);  
            for (int i = 0; i < params.length; i++) {  
                ps.setObject(i + 1, params[i]);  
            }  
            result = ps.executeUpdate();  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(null, ps);  
        }  
        return result;  
    }  
 
    /** 
     * 在事务下更新(不带参数) 
     * @param transId  事务ID 
     * @param sql  SQL语句 :"update table set price=200.00" 
     * @return 受影响行数 
     * @throws SQLException 
     */ 
    public int update(String transId, String sql) throws SQLException {  
        int result = 0;  
        Connection conn = cache.get(transId);  
        try {  
            PreparedStatement ps = conn.prepareStatement(sql);  
            result = ps.executeUpdate();  
        } catch (SQLException e) {  
            throw e;  
        }  
        return result;  
    }  
 
    /** 
     * 在事务下更新(带参数) 
     * @param transId 事务ID 
     * @param sql SQL语句 :"delete from table where id=?" 
     * @param params 参数对象数组 :new Object[]{参数1,参数2,...} 
     * @return 受影响行数 
     * @throws SQLException 
     */ 
    public int update(String transId, String sql, Object[] params)  
            throws SQLException {  
        int result = 0;  
        Connection conn = cache.get(transId);  
        try {  
            PreparedStatement ps = conn.prepareStatement(sql);  
            for (int i = 0; i < params.length; i++) {  
                ps.setObject(i + 1, params[i]);  
            }  
            result = ps.executeUpdate();  
        } catch (SQLException e) {  
            throw e;  
        }  
        return result;  
    }  
 
    /** 
     * 非事务下批量更新 
     * @param sql  SQL语句 :"insert into table(p1,p2,p3) values(?,?,?)" 
     * @param params 参数集合List<Object[]> 其中new Object[]{参数1,参数2,...} 
     * @return 受影响行数 
     * @throws SQLException 
     */ 
    public int[] batchUpdate(String sql, List<Object[]> params)  
            throws SQLException {  
        int[] result = new int[params.size()];  
        Connection conn = null;  
        PreparedStatement ps = null;  
        try {  
            conn = getConn();  
            conn.setAutoCommit(false);  
            ps = conn.prepareStatement(sql);  
            for (Object[] objects : params) {  
                for (int i = 0; i < objects.length; i++) {  
                    ps.setObject(i + 1, objects[i]);  
                }  
                ps.addBatch();  
            }  
            result = ps.executeBatch();  
            conn.commit();  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(null, ps);  
        }  
        return result;  
    }  
 
    /** 
     * 在事务下批量更新 
     * @param transId 事务ID 
     * @param sql SQL语句 :"insert into table(p1,p2,p3) values(?,?,?)" 
     * @param params 参数集合List<Object[]> 其中new Object[]{参数1,参数2,...} 
     * @return 受影响行数 
     * @throws SQLException 
     */ 
    public int[] batchUpdate(String transId, String sql, List<Object[]> params) throws SQLException {  
        int[] result = new int[params.size()];  
 
        Connection conn = cache.get(transId);  
        PreparedStatement ps = conn.prepareStatement(sql);  
        for (Object[] objects : params) {  
            for (int i = 0; i < objects.length; i++) {  
                ps.setObject(i + 1, objects[i]);  
            }  
            ps.addBatch();  
        }  
        result = ps.executeBatch();  
        return result;  
    }  
 
    /** 
     * 查询(不带参数)返回List<Map<k,v>>其中k:字段名小写,v:字段值 
     * @param sql SQL语句 :"select * from table" 
     * @return 集合List<Map<k,v>> 其中k:字段名小写,v:字段值 
     * @throws SQLException 
     */ 
    public List<Map<String, Object>> query(String sql) throws SQLException {  
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();  
        Connection conn = null;  
        PreparedStatement ps = null;  
        ResultSet rs = null;  
        try {  
            conn = getConn();  
            ps = conn.prepareStatement(sql);  
            rs = ps.executeQuery();  
            ResultSetMetaData rsmd = rs.getMetaData();  
            int colCount = rsmd.getColumnCount();  
            while (rs.next()) {  
                Map<String, Object> map = new HashMap<String, Object>();  
                for (int i = 0; i < colCount; i++) {  
                    String key = rsmd.getColumnLabel(i + 1).toLowerCase();  
                    Object val = rs.getObject(i + 1) != null ? rs  
                            .getObject(i + 1) : "";  
                    map.put(key, val);  
                }  
                list.add(map);  
            }  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(rs, ps);  
        }  
        return list;  
    }  
 
    /** 
     * 分页查询(不带参数)返回List<Map<k,v>>其中k:字段名小写,v:字段值 
     * @param sql SQL语句 :"select * from table" 
     * @param currPage 第几页 
     * @param pageSize 每页记录数 
     * @return 集合List<Map<k,v>> 其中k:字段名小写,v:字段值 
     * @throws SQLException 
     */ 
    public List<Map<String, Object>> queryPager(String sql, int currPage,  
            int pageSize) throws SQLException {  
        String pageSql = getPageSql(sql, currPage, pageSize);  
        return query(pageSql);  
    }  
 
    /** 
     * 查询(带参数)返回List<Map<k,v>>其中k:字段名小写,v:字段值 
     * @param sql SQL语句 :"select * from table where id = ?" 
     * @param params 参数对象数组 :new Object[]{参数1,参数2,...} 
     * @return 集合List<Map<k,v>> 其中k:字段名小写,v:字段值 
     * @throws SQLException 
     */ 
    public List<Map<String, Object>> query(String sql, Object[] params) throws SQLException {  
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();  
        Connection conn = null;  
        PreparedStatement ps = null;  
        ResultSet rs = null;  
        try {  
            conn = getConn();  
            ps = conn.prepareStatement(sql);  
            for (int i = 0; i < params.length; i++) {  
                ps.setObject(i + 1, params[i]);  
            }  
            rs = ps.executeQuery();  
            ResultSetMetaData rsmd = rs.getMetaData();  
            int colCount = rsmd.getColumnCount();  
            while (rs.next()) {  
                Map<String, Object> map = new HashMap<String, Object>();  
                for (int i = 0; i < colCount; i++) {  
                    String key = rsmd.getColumnLabel(i + 1).toLowerCase();  
                    Object val = rs.getObject(i + 1) != null ? rs  
                            .getObject(i + 1) : "";  
                    map.put(key, val);  
                }  
                list.add(map);  
            }  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(rs, ps);  
        }  
        return list;  
    }  
 
    /** 
     * 分页查询(带参数)返回List<Map<k,v>>其中k:字段名小写,v:字段值 
     * @param sql SQL语句 :"select * from table where id = ?" 
     * @param params 参数对象数组 :new Object[]{参数1,参数2,...} 
     * @param currPage 第几页 
     * @param pageSize 每页记录数 
     * @return 集合List<Map<k,v>> 其中k:字段名小写,v:字段值 
     * @throws SQLException 
     */ 
    public List<Map<String, Object>> queryPager(String sql, Object[] params,  
            int currPage, int pageSize) throws SQLException {  
        String pageSql = getPageSql(sql, currPage, pageSize);  
        return query(pageSql);  
    }  
 
    /** 
     * 单值查询(不带参数) 
     * @param sql SQL语句 :"select name from table" 
     * @return 单值 
     * @throws SQLException 
     */ 
    public String scalar(String sql) throws SQLException {  
        String res = null;  
        Connection conn = null;  
        PreparedStatement ps = null;  
        ResultSet rs = null;  
        try {  
            conn = getConn();  
            ps = conn.prepareStatement(sql);  
            rs = ps.executeQuery();  
            if (rs.next()) {  
                res = String.valueOf(rs.getObject(1));  
            }  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(rs, ps);  
        }  
        return res;  
    }  
 
    /** 
     * 单值查询(带参) 
     * @param sql SQL语句 :"select name from table where id=?" 
     * @param params 参数对象数组 :new Object[]{参数1,参数2,...} 
     * @return 单值 
     * @throws SQLException 
     */ 
    public String scalar(String sql, Object[] params) throws SQLException {  
        String res = null;  
        Connection conn = null;  
        PreparedStatement ps = null;  
        ResultSet rs = null;  
        try {  
            conn = getConn();  
            ps = conn.prepareStatement(sql);  
            for (int i = 0; i < params.length; i++) {  
                ps.setObject(i + 1, params[i]);  
            }  
            rs = ps.executeQuery();  
            if (rs.next()) {  
                res = String.valueOf(rs.getObject(1));  
            }  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(rs, ps);  
        }  
        return res;  
    }  
 
    /** 
     * 执行存储过程 
     * @param procName 存储过程 
     * @param params 存储过程参数对象数组 :new Object[]{参数1,参数2,...} 
     * @param outParamNum 输出参数个数 
     * @return 输出参数 
     * @throws SQLException 
     */ 
    public String[] execProc(String procName, Object[] params, int outParamNum)  
            throws SQLException {  
        String[] ret = new String[outParamNum];  
        Connection conn = null;  
        CallableStatement cs = null;  
        int inParamNum = (null != params) ? params.length : 0;  
        String procSql = getProcSql(procName, inParamNum, outParamNum);  
        try {  
            conn = getConn();  
            cs = conn.prepareCall(procSql);  
            for (int i = 0; i < inParamNum; i++) {  
                cs.setObject(i + 1, params[i]);  
            }  
            for (int k = 1; k <= outParamNum; k++) {  
                cs.registerOutParameter(inParamNum + k, Types.VARCHAR);  
            }  
            cs.executeQuery();  
            for (int k = 1; k <= outParamNum; k++) {  
                ret[k - 1] = cs.getString(inParamNum + k);  
            }  
        } catch (SQLException e) {  
            throw e;  
        } finally {  
            closeAll(null, cs);  
        }  
        return ret;  
    }  
 
    /** 
     * 开始事务 
     * @return 事务ID 
     */ 
    public String beginTrans() {  
        String transId = null;  
        try {  
            Connection conn = getConn();  
            conn.setAutoCommit(false);  
            transId = UUID.randomUUID().toString();  
            cache.put(transId, conn);  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
        return transId;  
    }  
 
    /** 
     * 事务提交 
     * @param transId  事务ID 
     */ 
    public void commitTrans(String transId) {  
        Connection conn = null;  
        try {  
            conn = cache.get(transId);  
            conn.commit();  
            conn.setAutoCommit(true);  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            closeAll(null, null);  
            cache.remove(conn);  
        }  
    }  
 
    /** 
     * 事务回滚 
     * @param transId 事务ID 
     */ 
    public void rollbackTrans(String transId) {  
        Connection conn = null;  
        try {  
            conn = cache.get(transId);  
            conn.rollback();  
            conn.setAutoCommit(true);  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            closeAll(null, null);  
            cache.remove(conn);  
        }  
    }  
 
    /** 
     * 得到分页SQL语句 
     * @param sql 基本SQL语句 
     * @param currPage 当前页 
     * @param pageSize 每页记录数 
     * @return 分页SQL语句 
     */ 
    private String getPageSql(String sql, int currPage, int pageSize) {  
        StringBuffer pageSql = new StringBuffer(0);  
        if ("oracle".equalsIgnoreCase(dialect)) {  
            pageSql.append("SELECT * FROM(SELECT FA.*, ROWNUM RN FROM (");  
            pageSql.append(sql).append(") FA WHERE ROWNUM <= ");  
            pageSql.append(currPage * pageSize).append(")WHERE RN >= ").append(  
                    (currPage - 1) * pageSize + 1);  
        }  
        if ("mysql".equalsIgnoreCase(dialect)) {  
            pageSql.append(sql).append(" limit ").append(  
                    (currPage - 1) * pageSize).append(",").append(pageSize);  
        }  
        return pageSql.toString();  
    }  
 
    /** 
     * 得到存储过程语句 
     * @param procName 存储过程 
     * @param inParamNum 输入参数个数 
     * @param outParamNum 输出参数个数 
     * @return 
     * @throws SQLException 
     */ 
    private String getProcSql(String procName, int inParamNum, int outParamNum) throws SQLException {  
        StringBuffer sb = new StringBuffer();  
        sb.append("{call ").append(procName);  
        int paramCount = inParamNum + outParamNum;  
        if (paramCount > 0) {  
            sb.append("(");  
            for (int i = 0; i < paramCount; i++) {  
                sb.append("?");  
                if (i != paramCount - 1) {  
                    sb.append(",");  
                }  
            }  
            sb.append(")");  
        }  
        sb.append("}");  
        return sb.toString();  
    }  
      
    /** 
     * 测试DBUtil 
     * @param args 
     */ 
    public static void main(String[] args) {  
        try {  
            DBUtil dao = DBUtil.getInstance();  
            String sql0 = "select addd from operate";  
            String sql = "select * from rolepower rp where rolecode = (select ur.rolecode from user u left join userrole ur on u.code = ur.usercode where u.code = 0001)";  
            List<Map<String, Object>> list = dao.query(sql);  
            sql = "select * from operate";  
            String count = dao.scalar(sql0);  
            // list = dao.queryPager(sql, 1, 10);  
            System.out.println(count);  
            System.out.println(list.size());  
            // System.out.println(list.get(0).get("name"));  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  

}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/free0006/article/details/84115019

智能推荐

traefik-ingress 实现http自动跳转https_ingress httponly-程序员宅基地

文章浏览阅读3.1k次。简介Kubernetes目前ingress主流的就是nginx-ingress和traefik-ingress.nginx-ingress中实现http转https加一个注解就可以了,很简单。但是traefik-ingress好像稍微要复杂一点。现就将整个过程整理成文。条件1. Kubernetes集群2.集群已经安装traefik-ingress插件步骤1.部署nginx应用和服务#kubectl apply -f nginx.yamlapiVersion: apps.._ingress httponly

电脑防泄密系统如何构建企业数据防泄密架构-程序员宅基地

文章浏览阅读223次。这些加密技术,不仅可以支持图纸文档类型的文件加密如:cad,sloidworks,ug等二维三维图纸,还支持源代码的加密,如c、c++、c#、java等开发语言的支持。安秉电脑防泄密系统,还可以保护企业当数据发生泄漏时,可以进行日志查询,找到泄漏根源,从根本上解决数据泄密的事情发生。2,审批授权,对于涉密的数据,需要外发时,可以设置在线审批管理员授权,经过管理员审批后同意外发的数据方可带离公司电脑正常使用。4,报警,对于员电脑特殊的泄密行业,可以设置管理端报警,发现可疑情况立即报警,及时发现问题并且整改。

MATLAB时域分析(附完整代码)_matlab进行时域性能分析-程序员宅基地

文章浏览阅读845次,点赞10次,收藏10次。MATLAB时域分析(附完整代码)_matlab进行时域性能分析

git取消【删除】已经提交的文件(夹)跟踪_git rm --cached <file/folder>-程序员宅基地

文章浏览阅读754次。git取消【删除】已经提交的文件(夹)跟踪git rm -r --cached <fold> 不删除本地文件git rm -r --f <fold> 删除本地文件git rm --cached <file> 不删除本地文件,仅仅不再跟踪文件git rm --f <file> 删除本地文件,并且不再跟踪文件..._git rm --cached

django+ajax上传图片,预览并存储到数据库_django 使用ajax传递参数保存数据到sqlite-程序员宅基地

文章浏览阅读3k次,点赞2次,收藏23次。1、配置urlurls.py中配置地址2、在models.py中创建类class Pictures(models.Model): pic = models.ImageField(upload_to='onlineBug/media') def __str__(self): return self.pic3、在views.py中添加如下代码class U..._django 使用ajax传递参数保存数据到sqlite

51单片机蜂鸣器_51单片机对蜂鸣器的控制-程序员宅基地

文章浏览阅读662次,点赞6次,收藏8次。本文详细介绍了51单片机与蜂鸣器的工作原理、连接方式以及编程控制方法,并列举了它们在报警系统、定时器提示、电子乐器以及车辆倒车提示等场景中的应用实例。为了实现更丰富的声音效果,我们还可以通过编程控制GPIO引脚的输出频率和占空比来调节蜂鸣器的发声频率和音量。为了实现不同的声音效果,我们可以使用定时器/计数器来产生特定频率的脉冲信号,从而控制蜂鸣器的发声频率和音调。同时,51单片机还具备丰富的外设接口,如GPIO(通用输入输出)、定时器/计数器、串行通信接口等,方便与外部设备进行连接和控制。_51单片机对蜂鸣器的控制

随便推点

【Linux】Linux cgroup(Control Groups)常见用法_cgroup监控资源状态-程序员宅基地

文章浏览阅读250次,点赞3次,收藏5次。Linux cgroup(Control Groups)是一种强大的资源管理工具,它允许系统管理员对系统资源进行细粒度的控制。cgroup通过将进程分组并对这些组施加限制,从而实现资源的隔离和优先级控制。_cgroup监控资源状态

php dynamic library,PHP Startup: Unable to load dynamic library 问题。-程序员宅基地

文章浏览阅读845次。PHP Startup: Unable to load dynamic library … (tried:… 这种算是比较常见的问题,当然这里只讨论在保证 php.ini 中启用了相关扩展,并且相应的.dll文件确实存在于加载目录中的情况。我个人遇到的是’pdo_firebird’和 ‘pdo_oci’.D:\Tool\php\php-7.2.7-Win32-VC15-x64>phpWarn..._unable to load dynamic library 'pdo_firebird

web3之以太坊链二层(layer2):StarkNet_ethereum layer 2 network starknet-程序员宅基地

文章浏览阅读1.3k次,点赞27次,收藏22次。StarkWare公司一直致力于通过零知识证明(ZK)来解决区块链扩容问题,先后研发了2个L2方案——StarkEx和StarkNet。_ethereum layer 2 network starknet

网页方向培训—JavaScript第二讲_当修改文本框内容后,触发onchange事件,调用check函数-程序员宅基地

文章浏览阅读340次。JavaScript第二讲一、事件响应1.1 什么是事件&nbsp;&nbsp;JavaScript 创建动态页面。事件是可以被 JavaScript 侦测到的行为。 网页中的每个元素都可以产生某些可以触发 JavaScript 函数或程序的事件。比如说,当用户单击按钮或者提交表单数据时,就发生一个鼠标单击(onclick)事件,需要浏览器做出处理,返回给用户一个结果。..._当修改文本框内容后,触发onchange事件,调用check函数

java语言的命题原则_《 Java 语言程序设计(一) 》 课程全国统一命题考试说明 _ 重庆自考网...-程序员宅基地

文章浏览阅读68次。《 Java 语言程序设计(一) 》 课程全国统一命题考试说明为组织好高等教育自学考试 《 Java 语言程序设计(一) ) )课程的全国统一考试命题工作,根据全国统一命题课程的有关规定,特制定本说明。一、考试原则1 .考试标准本课程考试参照全日制普通高校同专业、同层次、同课程的 Java 语言程序设计(一)本科结业水平,并体现自学考试以培养应用型人才为主要目标的特点。在题量匕能够使中等水平的考生...

微信二维码转换成链接_微信二维码链接-程序员宅基地

文章浏览阅读6w次,点赞9次,收藏35次。微信二维码转换成链接我们很多人都在想,怎样才能把二维码转换成网址链接,然后点击网址链接就直接进入二维码呢?下面就是转换成链接的方法之一:微信转链接步骤一:打开https://cli.im/deqr然后上传你的二维码图片,然后得到解码网址(如下图);步骤二:http://qr.topscan.com/api.php?text= 然后加上你的解码后的网址;步骤三:http://h5..._微信二维码链接

推荐文章

热门文章

相关标签