使用微信js

您所在的位置:网站首页 如何在微信上下载音频到本地 使用微信js

使用微信js

2024-07-17 06:04:33| 来源: 网络整理| 查看: 265

JSSDK使用步骤

 

步骤一:绑定域名

先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

 

步骤二:引入JS文件

在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

备注:支持使用 AMD/CMD 标准模块加载方法加载

 

步骤三:通过config接口注入权限验证配置

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名 jsApiList: [] // 必填,需要使用的JS接口列表 });

签名算法见文末的附录1,所有JS接口列表见文末的附录2

 

步骤四:通过ready接口处理成功验证

wx.ready(function(){ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 });

 

步骤五:通过error接口处理失败验证

wx.error(function(res){ // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 });

 

接口调用说明

所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:

1.success:接口调用成功时执行的回调函数。

2.fail:接口调用失败时执行的回调函数。

3.complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。

4.cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。

5.trigger: 监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。

备注:不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回。

以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:

调用成功时:"xxx:ok" ,其中xxx为调用的接口名

用户取消时:"xxx:cancel",其中xxx为调用的接口名

调用失败时:其值为具体错误信息

 

音频接口

 

开始录音接口 wx.startRecord();

 

停止录音接口 wx.stopRecord({ success: function (res) { var localId = res.localId; } });

 

监听录音自动停止接口 wx.onVoiceRecordEnd({ // 录音时间超过一分钟没有停止的时候会执行 complete 回调 complete: function (res) { var localId = res.localId; } });

 

播放语音接口 wx.playVoice({ localId: '' // 需要播放的音频的本地ID,由stopRecord接口获得 });

 

暂停播放接口 wx.pauseVoice({ localId: '' // 需要暂停的音频的本地ID,由stopRecord接口获得 });

 

停止播放接口 wx.stopVoice({ localId: '' // 需要停止的音频的本地ID,由stopRecord接口获得 });

 

监听语音播放完毕接口 wx.onVoicePlayEnd({ success: function (res) { var localId = res.localId; // 返回音频的本地ID } });

 

上传语音接口 wx.uploadVoice({ localId: '', // 需要上传的音频的本地ID,由stopRecord接口获得 isShowProgressTips: 1, // 默认为1,显示进度提示 success: function (res) { var serverId = res.serverId; // 返回音频的服务器端ID } });

备注:上传语音有效期3天,可用微信多媒体接口下载语音到自己的服务器,此处获得的 serverId 即 media_id,参考文档 .目前多媒体文件下载接口的频率限制为10000次/天,如需要调高频率,请登录微信公众平台,在开发 - 接口权限的列表中,申请提高临时上限。

下面开始码代码:

voice.js

 

var URIstring=location.href.split('#')[0];//获取当前页面的全路径 var url="/zf/ConfigParam?Rurl="+encodeURIComponent(URIstring);//将路径传入后台加密时使用 $(document).ready(function(){ $.ajax({ url :encodeURI(url),// encodeURI(encodeURI(url)), type : 'POST', async: false, dataType : 'json', timeout : 5000,     error: function(XMLHttpRequest, textStatus, errorThrown) {     alert("不好意思,出了点小问题");     },     success : function(req) {  wx.config({     debug: false,//开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。                     appId: req.appid, // 必填,公众号的唯一标识                     timestamp:req.timestamp, // 必填,生成签名的时间戳    nonceStr: req.nonceStr, // 必填,生成签名的随机串     signature:req.signature,// 必填,签名,见附录1    jsApiList:['chooseImage','previewImage','uploadImage','downloadImage',]// 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });  }

});

  var voice = { localId: '',   serverId: ''  };//全局变量

 var END;  var START;  //按下开始录音  $('#talk_btn').on('touchstart', function(event){      event.preventDefault();      START = new Date().getTime();      recordTimer = setTimeout(function(){          wx.startRecord({              success: function(){         // mui('#talk_btn').button('loading');                  localStorage.rainAllowRecord = 'true';              },              cancel: function () {                  alert('用户拒绝授权录音');              }          });      },300);

 });

 

  //松手结束录音  $('#talk_btn').on('touchend', function(event){      event.preventDefault(); //  mui('#talk_btn').button('reset');      END = new Date().getTime();      if((END - START) < 1000){          END = 0;          START = 0;          //小于1000ms,不录音          clearTimeout(recordTimer); mui.toast('录音时长小于1秒不录音',{ duration:'short', type:'div' }) ;  var t=setTimeout(function(){wx.stopRecord()},800);//这里设置800毫秒,是因为如果用户录音之后马上松开按钮,会成 wx.stopRecord不起作用的情况,然后会一直录音,所以时间设置长一点              //clearTimeout(t);      }else{          wx.stopRecord({            success: function (res) {              voice.localId = res.localId;              //$("#vo").val(res.localId);            uploadVoice();            },            fail: function (res) {              alert(JSON.stringify(res));            }          });      }

 });

//上传录音  function uploadVoice(){      //调用微信的上传录音接口把本地录音先上传到微信的服务器      //不过,微信只保留3天,而我们需要长期保存,我们需要把资源从微信服务器下载到自己的服务器      wx.uploadVoice({          localId: voice.localId, // 需要上传的音频的本地ID,由stopRecord接口获得          isShowProgressTips: 1, // 默认为1,显示进度提示          success: function (res) {          voice.serverId = res.serverId;                 /* var uu = /restsh/uploadVoice/" + res.serverId;         $.ajax({//上传到服务器         url : uu,         async : true,         cache : false,         dataType : 'json',         type : 'GET',         data : {},         success : function(req) {         voice.serverId = res.serverId;           $.web.RemoveLoading();         },         error : function(XMLHttpRequest, textStatus, errorThrown) {         $.web.RemoveLoading();         mui.alert("不好意思,出了点小问题","提示","确定");         }         });*/          }      });

 }

            // 4.4 监听录音自动停止  wx.onVoiceRecordEnd({    complete: function (res) {      voice.localId = res.localId;      //uploadVoice();//上传录音到服务器      alert('录音时间已超过一分钟');    }

 });

 

 document.querySelector('#playVoice').onclick = function () {    if (voice.localId == '') {     alert('请先录制一段声音');      //alert('请先使用 startRecord 接口录制一段声音');      return;    }      wx.playVoice({          localId: voice.localId        });  

 };

 

           // 暂停播放音频  document.querySelector('#stop_btn').onclick = function () {    mui('#playVoice').button('reset');    wx.pauseVoice({      localId: voice.localId    });  };

  /*使用微信jssdk接口录音,在同一个域只需要授权一次,即第一次使用录音的时候,微信自己会弹出对话框询问是否允许录音,用户点击允许后,之后再使用录音时,便不会再咨询用户是否允许。  在第一次按住录音后,由于用户未曾允许录音,微信会提示用户授权允许在本页面使用微信录音功能,这时用户会放开录音按钮转而去点击允许,在用户允许后,才真正会开始录音,而此时用户早已放开录音按钮,那么录音按钮上便不会再有touchend事件,录音便会一直进行。  解决策略:使用localStorage记录用户是否曾授权,并以此来判断是否需要在刚进入页面是自动录一段录音来触发用户授权*/  if(!localStorage.rainAllowRecord || localStorage.rainAllowRecord !== 'true'){      wx.startRecord({          success: function(){              localStorage.rainAllowRecord = 'true';              setTimeout(function(){                    wx.stopRecord({                        fail:function(res){                            //alert("停止失败");                        },                        success: function (res) {                            var localId = res.localId;                        }                    });                },800);//这里设置800毫秒,是因为如果用户录音之后马上松开按钮,会成 wx.stopRecord不起作用的情况,然后会一直录音,所以时间设置长一点              //clearTimeout(t);          },          cancel: function () {              alert('用户拒绝授权录音');          }      });

 }

wx.error(function (res) {             wx.stopRecord();  alert(res.errMsg); });

以上是前端js,具体业务具体操作

 

后台代码

ConfigParam.java

 

 

import java.io.IOException; import java.io.PrintWriter; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONObject; public class ConfigParam extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  response.setCharacterEncoding("UTF-8");           PrintWriter out = response.getWriter();   String Rurl=java.net.URLDecoder.decode(request.getParameter("Rurl"),"utf-8"); //System.out.println(Rurl);  Map ret= WeixinUtil.getJSSDKData(Rurl,WechatUtil.appId,WechatUtil.appSecret);  JSONObject json=JSONObject.fromObject(ret);         //System.out.println(json.toString());         out.print(json); } }

WeixinUtil.java  和AccessToken.java

 

import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ConnectException; import java.net.URL; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import net.sf.json.JSONException; import net.sf.json.JSONObject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /**  * 公众平台通用接口工具类  *   *   *   */ public class WeixinUtil { private static Log log = LogFactory.getLog(WeixinUtil.class); // 获取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?            grant_type=client_credential&appid=APPID&secret=APPSECRET"; private static  Map  tokenMap = new HashMap(); /**  * 获取access_token  *   * @param appid 凭证  * @param appsecret 密钥  * @param flag 是否重新获取  * @return  */ public static AccessToken getAccessToken(String appid, String appsecret,boolean flag) { AccessToken accessToken = null; log.info("=================getAccessToken-start"); if(!flag){ accessToken = tokenMap.get(appid); } long now = System.currentTimeMillis(); if(accessToken != null && !flag){ long lastTime = accessToken.getCreateTime(); //当accessToken还在有效期内 if(now try { accessToken = new AccessToken(); accessToken.setCreateTime(now); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in") - 300); log.info("重新获取accessToken=="+accessToken); } catch (JSONException e) { accessToken = null; // 获取token失败 log.error("获取token失败 errcode:"+jsonObject.getInt("errcode")+" errmsg:{"+ jsonObject.getString("errmsg")+"}" ); } } log.info("=================getAccessToken-end"); tokenMap.put(appid, accessToken); return accessToken; } /**  * 获取access_token  *   * @param appid 凭证  * @param appsecret 密钥  * @return  */ public static AccessToken getAccessToken(String appid, String appsecret ) { log.info("getAccessToken:重新获取AccessToken"); return getAccessToken(appid, appsecret, true); } public static String JS_API_URL =  "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";   /**  *   * @param accessToken  * @return  */ public static String getJsapi_ticket(String accessToken){ log.info("=====================getJsapi_ticket:start");      String url = JS_API_URL.replace("ACCESS_TOKEN", accessToken);      JSONObject json = httpRequest(url, "GET", null);      log.info("getJsapi_ticket:"+json);         String jsapi_ticket = "";         try { jsapi_ticket = json.getString("ticket"); } catch (Exception e) { log.error("=====================getJsapi_ticket:error"+json); e.printStackTrace(); }      log.info("=====================getJsapi_ticket:end");         return jsapi_ticket;     } //JS SDK  中需要的相关的数据 private  static Map JsSDKMap = new HashMap(); public static String getJsapi_ticket_cache(String accessToken ){ String jsapi = JsSDKMap.get(accessToken); if(jsapi != null){ log.info("读取jsapi_ticket缓存"+jsapi ); return jsapi; }else{ jsapi = getJsapi_ticket(accessToken); log.info("刷新Jsapi_ticket:"+jsapi+"===="+accessToken ); JsSDKMap.put(accessToken, jsapi); }         return jsapi;     } //获得jsapi_ticket,noncestr,timestamp    public static  Map getJSSDKData(String requestUrl,String appid,String appsecret){ log.info("=================getJSSDKData-start"); //1)获取access_token AccessToken accessToken =  getAccessToken(appid, appsecret,false); String token = accessToken.getToken(); log.info("accessToken:"+accessToken); //2)获取jsapi_ticket(有效期7200秒 String jsapi_ticket = getJsapi_ticket_cache(token); log.info("jsapi_ticket:"+jsapi_ticket); //3)获取//随机字符串  String noncestr  = Double.toString(Math.random()).substring(2, 15);//随机字符串 //4)获取 随机时间戳 String timeStamp =((int)(new Date().getTime()/1000))+"";//随机时间戳 //5)获取签名 String str = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + noncestr + "×tamp="+ timeStamp +"&url=" + requestUrl; log.info("str:" + str); String signature = SHA1Util.Sha1(str);      Map  map =  new HashMap();     map.put("ticket", jsapi_ticket); map.put("noncestr", noncestr); map.put("timestamp", timeStamp); map.put("signature", signature); map.put("url", requestUrl); map.put("appid", appid); log.info("=================getJSSDKData-end"); return map; }    /**  * 发起https请求并获取结果  *   * @param requestUrl 请求地址  * @param requestMethod 请求方式(GET、POST)  * @param outputStr 提交的数据  * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)  */ public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; StringBuffer buffer = new StringBuffer(); try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect(); // 当有数据需要提交时 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { log.error("Weixin server connection timed out."); } catch (Exception e) { log.error("https request error:{}", e); } return jsonObject; }

}

 

/**   * 微信通用接口凭证   *    *   *   */   public class AccessToken {       // 获取到的凭证       private String token;       // 凭证有效时间,单位:秒       private int expiresIn;           private long createTime;        public String getToken() {           return token;       }          public void setToken(String token) {           this.token = token;       }         public int getExpiresIn() {           return expiresIn;       }         public void setExpiresIn(int expiresIn) {           this.expiresIn = expiresIn;       } public long getCreateTime() { return createTime; } public void setCreateTime(long createTime) { this.createTime = createTime; }   } 

uploadVoice

 

 

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  request.setCharacterEncoding("UTF-8");       response.setCharacterEncoding("UTF-8");       PrintWriter out = response.getWriter();  //String mediaId=request.getParameter("mediaId"); Map map = new HashMap(); String mediaId = request.getParameter("mediaId"); String folderName="/app/ss/"+new SimpleDateFormat("yyyy/MMdd/").format(new Date()); try { File dir = new File(folderName); if (!dir.exists()) dir.mkdirs(); } catch (Exception ex) { }    String Str=""; String  randstr = UUID.randomUUID().toString().replaceAll("-", ""); String path=folderName+randstr;//绝对路径 String frontName = "" + randstr;//相对路径 String absFileName=path+".jpg";//"D:\\img\\a.jpg";// String str= DloadImgUtil.downloadMedia(mediaId, absFileName,path+"_240.mp3","2");//调用下载接口 map.put("status", "1"); map.put("msg",Str); map.put("path", ""); map.put("photoUrl",""); JSONObject json = JSONObject.fromObject(map);    out.print(json); }

记住,大坑来了,由于从微信服务器下载下来的音频格式是amr格式的,为了实现使用h5标签能够播放,需要转成mp3格式

我是使用ffmpeg进行转换的

使用ffmpeg将amr格式转为mp3格式时需注意:windows系统使用ffmpeg.exe,linux系统使用ffmpeg(去官网下载对应版本http://ffmpeg.org/download.html)

DloadVoicUtil.java

 

public class DloadImgUtil { private final static String FFMPEG_PATH;       static {           FFMPEG_PATH =DloadImgUtil.class.getResource("ffmpeg.exe").getFile(); //windows系统使用, FFmpeg文件和DloadImgUtil 同一目录下

    }  

 //  static {       //   FFMPEG_PATH =DloadImgUtil.class.getResource("ffmpeg").getFile(); //linux使用    //}  

public static String downloadMedia(String mediaId, String savePath,String out,String type) { String filePath = null; AccessToken accessToken = WeixinUtil.getAccessToken(WechatUtil.appId, WechatUtil.appSecret, false); // 拼接请求地址 String requestUrl = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID"; requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken.getToken()) .replace("MEDIA_ID", mediaId); String returnstr="0"; BufferedInputStream bis = null; FileOutputStream fos = null; HttpsURLConnection conn = null; try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); // URL url = new URL(null,requestUrl,new // sun.net.www.protocol.https.Handler()); // URL url = new URL(requestUrl); URL url = new URL(requestUrl); conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求方式(GET/POST) conn.setRequestMethod("GET"); // 根据内容类型获取扩展名 // String fileExt = DloadImgUtil // .getFileexpandedName(conn.getHeaderField("Content-Type")); // 将mediaId作为文件名 filePath = savePath; bis = new BufferedInputStream(conn.getInputStream()); fos = new FileOutputStream(new File(filePath)); byte[] buf = new byte[8096]; int size = 0; while ((size = bis.read(buf)) != -1) fos.write(buf, 0, size); amr2mp3(savePath,out);   } catch (Exception e) {   returnstr="-1";   e.printStackTrace(); } finally { // 释放资源 conn.disconnect(); try { // 关闭流,释放资源 if (fos != null) { fos.close(); } if (bis != null) { bis.close(); } } catch (Exception e) { e.getStackTrace(); } } return returnstr;

}

   /**       * 将一个amr文件转换成mp3文件       * @param amrFile        * @param mp3File        * @throws IOException        *    -i :指定输入文件-ar : 指定sampling rate(采样率),它的单位是HZ      *  -ac:指定声道,1表示双声道,0表示单声道-ab:指定转换后的比特率 * @throws InterruptedException       */       public static void amr2mp31(String amrFileName, String mp3FileName) throws IOException, InterruptedException {           Runtime runtime = Runtime.getRuntime();           Process process = runtime.exec(FFMPEG_PATH + " -i "+amrFileName+" -ar 8000 -ac 1 -y -ab 12.5k " + mp3FileName); //12.4         InputStream in = process.getErrorStream();           BufferedReader br = new BufferedReader(new InputStreamReader(in));           try {               String line = null;               while((line = br.readLine())!=null) {              //     System.out.println(line);               }               while((line = br.readLine())!=null){                       System.out.println("");                       int exitValue =process.waitFor();                       System.out.println("Process exitValue="+exitValue);               }           } finally {               //为了避免这里抛出的异常会覆盖上面抛出的异常,这里需要用捕获异常。               try {                   in.close();               } catch (Exception e) {                   e.printStackTrace();               }           }       } 

 

 

 

 

 

 

 

 



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭