使用HTML5實現掃描PC二維碼且觸發WAP端上傳資源功能

腫諏遜汲發表於2020-09-22

  講解一篇Java程式碼根據引數動態生成PC二維碼效果,且成功掃描並上傳圖形或影片資源的功能。

  技術難度一般,關鍵在於如何把一整套邏輯思路整合到專案上,如果呼叫,應該到哪些技術,理清了互動關係,詳細對於大家而言這就是一份入門級別的程式碼參考,以作提升。

  粗略介紹一下應用到的技術問題,前端方法使用簡單的html元素佈局,生成<img>二維碼即可,後端框架為SpringMVC,結構簡單,查閱清晰,應用到的二維碼Jar包為:qrcode_swetake.jar 。

  一、從前端開始入手,先構建頁面佈局確保能夠生成二維碼效果:

  wKioL1g2UXHSrH92AACHsh0s-6Y009.jpg

  實現出來的成型效果如上圖所示,滑鼠移入移出則顯示隱藏二維碼效果框,自行慢慢摸索CSS如何實現了,這裡需要說明的是二維碼只需要一句話即可動態生成。

  <c:set var="ctx" value="${pageContext.request.contextPath}"></c:set>

  <img src="${ctx}/upload/codeImg.html?userId=${loginUserId}" />

  設定一個<img>標籤動態生成接收返回的二維碼圖,高寬度自行根據實際情況設定,然後就嗶的一聲手機即可訪問的,當然測試階段請確保IP同在一個區域網。

  掃描出來的頁面也異曲同工,關鍵在於你要設計成什麼樣子,只要能實現上傳功能即可。

  我應用的前端上傳外掛為jquery.form.js,主要JS方法如下:

  <input type="file" name="tempFile" id="tempFile"

  accept= ".avi,.mpg,.mp4,.mov;capture=camera" >

  <input type="file" name="tempFile" id="tempFile"

  accept= "p_w_picpath/jpg,p_w_picpath/JPG,p_w_picpath/jpeg,p_w_picpath/JPEG,p_w_picpath/pdf,p_w_picpath/png;capture=camera"

  >

  <script language="javascript">

  function previewFile(id){

    var x = document.getElementById("tempFile");

    if(!x || !x.value) return;

    var patn = /\.jpg$|\.JPG$|\.jpeg$|\.JPEG$|\.pdf$|\.PDF$|\.png$|\.PNG$/;

    var inpType = "p_w_picpath\/jpg,p_w_picpath\/JPG,p_w_picpath\/jpeg,p_w_picpath\/JPEG,p_w_picpath\/pdf,p_w_picpath\/PDF,p_w_picpath\/png,p_w_picpath\/PNG";

    var type = $("#type").val();

    if(type=='video'){

    patn = /\.mp4$|\.MP4$|\.mov$|\.MOV$/;

    inpType = ".MP4,.MOV,.mp4,.mov";

    }

    if(!patn.test(x.value)){

    if(type=='video'){

    alertMsg("請上傳mov、mp4格式的影片");

    }else{

    alertMsg("請上傳jpg、png、pdf格式的檔案");

    }

    }else{

            initShow();

      $("#uploadForm").ajaxSubmit(options);

    }

  }

  var options  = {

  dataType:"json",

  url:'${ctx}/upload/uploadAndSaveFile.html',

  type:'post',

  contentType: "application/x-www-form-urlencoded; charset=utf-8",

  success:function(data)  {

  initHide();

  if(data.success){

  //alertCallBack("上傳成功<br/>請前往PC端重新整理後查閱!",function(){

  document.location.href="${ctx}/upload/toUploadEndDetail.html";

  //});

  }else{

  alertCallBack(data.message,function(){

  window.location.reload();

  });

  //alertMsg(data.message);

  }

  },

  error :function(data){

  initHide();

  alertMsg(data);

  },

  beforeSubmit:showRequest  // pre-submit callback

  //clearForm:true

  };

  function showRequest(formData, jqForm, options) {

  var queryString = $.param(formData);

  }

  </script>

  以上程式碼由於涉及公司內部邏輯,故存在個別地方的刪減動作,但整體思路已清晰羅列出來了。

  這裡需要講到一個應用到的UI外掛,即alertMsg使用到的hint彈出框效果。smallarAlert.js

  附件資源均會統一部署上來,外掛自適應效果可相容IE、谷歌、360、火狐等主流瀏覽器,內建樣式及功能等也可自行重寫,具體應用自行度娘搜尋該外掛了,這裡就不一一講解了。

  二、從後端著手處理二維碼生成技術及資源儲存動作:

  /**

   * @Descript :生成二維碼圖片url

   * @author : Teny_lau

   * @CreatedTime : 2016年11月21日-下午3:44:44

   * @param model

   * @param request

   * @param response

   */

  @RequestMapping("/codeImg")

  public void toCodeImg(Model model, HttpServletRequest request, HttpServletResponse response) {

  String localIp = getInternetIp(request);

  String path = request.getSession().getServletContext().getContextPath();

  String port = StringUtils.getNullBlankStr(request.getServerPort());// 獲取伺服器埠

  String userId = StringUtils.getNullBlankStr(request.getParameter("userId"));//接收引數

  String params = "userId=" + userId;

  // 位元組長度須控制在124個長度以內,否則報異常陣列索引值溢位

  String content = localIp + ":" + port + path + "/upload/toUploadMain.html?" + params;

  EncoderHandler encoder = new EncoderHandler();

  encoder.encoderQRCoder(content, response);

  }

  private String getInternetIp(HttpServletRequest request) {

  String ip = StringUtils.getNullBlankStr(request.getHeader("x-forwarded-for"));

  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

  ip = StringUtils.getNullBlankStr(request.getHeader("Proxy-Client-IP"));

  }

  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

  ip = StringUtils.getNullBlankStr(request.getHeader("WL-Proxy-Client-IP"));

  }

  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

  ip = StringUtils.getNullBlankStr(request.getRemoteAddr());// 獲取客戶端IP地址

  }

  String localIp = "";// 獲取網段地址

  try {

  InetAddress localInter = InetAddress.getLocalHost();

  localIp = StringUtils.getNullBlankStr(localInter.getHostAddress());

  } catch (UnknownHostException e1) {

  e1.printStackTrace();

  }

  if (!ip.equals(localIp) && !"127.0.0.1".equals(ip)) {

  // 當程式獲取非伺服器網口時,自動重置為本地網口

  ip = localIp;

  }

  if ("127.0.0.1".equals(ip)) {

  // 根據網路卡取本機配置的IP

  InetAddress inet = null;

  try {

  inet = InetAddress.getLocalHost();

  } catch (Exception e) {

  e.printStackTrace();

  }

  ip = StringUtils.getNullBlankStr(inet.getHostAddress());

  }

  // 對於透過多個代理的情況,第一個IP為客戶端真實IP,多個IP按照','分割

  if (ip != null && ip.length() > 15) { // "***.***.***.***".length() = 15

  if (ip.indexOf(",") > 0) {

  ip = ip.substring(0, ip.indexOf(","));

  }

  }

  return ip;

  }

  /**

   * 提交資源資訊

   *

   * @param model

   * @param request

   * @return

   */

  @RequestMapping("uploadAndSaveFile")

  @ResponseBody

  public void uploadAndSaveFile(HttpServletRequest request, HttpServletResponse response) {

  Map<String, Object> result = new HashMap<String, Object>();

  try {

  String type = StringUtils.getNullBlankStr(request.getParameter("type"));

  saveUploadFile(request);

  result.put("success", true);

  } catch (RuntimeException run) {

  result.put("success", false);

  result.put("message", run.getMessage());

  } catch (Exception e) {

  result.put("success", false);

  result.put("message", "上傳失敗<br/>請重新或掃碼上傳!");

  // FileUtil.deleteFiles(fileNames);

  }

  try {

  response.setContentType("text/html;charset=gbk");

  JSONObject jsonObj = JSONObject.fromObject(result);

  response.getWriter().print(jsonObj);

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  /**

   * @Descript :儲存上傳資源

   * @author : Teny_lau

   * @CreatedTime : 2016年11月21日-下午3:28:39

   */

  private void saveUploadFile(HttpServletRequest request) {

  String userId = StringUtils.getNullBlankStr(request.getParameter("userId"));//接收引數

  Map<String, Object> queryMap = new HashMap<String, Object>();

  queryMap.put("","");

  List<XXX> flashList = new ArrayList<XXX>();

  String oldFlashName = "";// 舊檔案

  //由於以下邏輯存在專案程式碼,故以下物件均為舉例說明,具體要求視專案自行修改

  Old oldEntity = new Old();

  if (flashList != null && flashList.size() > 0) {

  oldEntity = flashList.get(0);

  //獲取已上傳的舊檔名,便於在插入新檔案時,刪除舊檔案,避免資源過多佔用空間記憶體

  oldFlashName = oldEntity.getFlashName();

  }

  MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;

  CommonsMultipartFile file1 = (CommonsMultipartFile) multipartRequest.getFile("tempFile");// 上傳資源引數

  if (file1 != null && !file1.isEmpty()) {

  // 判斷上傳資源等檔案大小 控制在500M以內,自行根據專案要求斟酌

  int maxSize = 500 * 1024 * 1024;

  if (file1.getSize() >= maxSize) {

  throw new RuntimeException("儲存失敗,檔案控制在500M以內");

  }

  String fileName = saveFile(file1, request, oldFlashName);//這裡返回的為重新命名新檔名稱

  }

  }

  private String saveFile(CommonsMultipartFile file, HttpServletRequest request, String oldFileName) {

  String fileName = file.getOriginalFilename();

  String uploadPath = request.getSession().getServletContext().getRealPath(FILEPATH);

  // 判斷是否有上傳檔案

  File targetFile = null;

  String groupId = StringUtils.getNullBlankStr(request.getParameter("groupId"));//接收引數

  String newTransFileName = DateUtils.getCurrentDateTime14() + groupId + "." + org.apache.commons.lang3.StringUtils.substringAfterLast(fileName, ".");

  String newFilePath = uploadPath + File.separator + newTransFileName;

  try {

  targetFile = new File(new StringBuilder().append(newFilePath).toString());

  // 檔案重新命名

  file.transferTo(targetFile);

  String oldFilePath = "";

  if (StringUtils.isNotBlank(oldFileName)) {

  oldFilePath = uploadPath + File.separator + oldFileName;

  FileUtil.delSingleFile(oldFilePath);

  }

  // 複製檔案到指定盤

  // CopyFileUtil.copyFile(origiNewPath, oldFilePath, true);

  } catch (NullPointerException e) {

  e.printStackTrace();

  } catch (Exception e) {

  e.printStackTrace();

  }

  return newTransFileName;

  }

  程式碼先一一貼上,以上程式碼由於存在公司邏輯,故也做了個別刪減動作,但整體思路的增刪改上傳等功能已一一展示在這裡了。

  個別工具類方法如下:

  1、StringUtils.getNullBlankStr

  /**

  * 功能描述:

  * 判斷字串是否為null或為空字串,則返回空字串""

  *

  * @param obj String

  *            待檢查的字串

  * @return String

  *         如果為null或空字串(包括只含空格的字串)則返回"",否則返回原字串去空格

  */

  public static String getNullBlankStr(Object obj) {

  if (obj == null) {

  return "";

  } else {

  return obj.toString().trim();

  }

  }

  校驗判斷為空時則返回空字串的動作。

  2、DateUtils.getCurrentDateTime14()

  /**

   * 獲取當前應用伺服器的系統日期時間

   *

   * @return 日期時間字串,格式:yyyyMMddHHmmss

   */

  public static String getCurrentDateTime14() {

  DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");

  return df.format(new Date(System.currentTimeMillis()));

  }

  具體時間格式可自行定義,根據具體情況而定。

  3、EncoderHandler和FileUtil 工具類,參考附件檔案原始碼。

  特別注意:

  這裡的EncoderHandler需要提醒到的一個問題點是,該方法接收位元組長度是有最大值限制的,即最大可儲存124個字元,超出長度則報資料越界異常。

  public void encoderQRCoder(String content, HttpServletResponse response) {

  try {

  Qrcode handler = new Qrcode();

  handler.setQrcodeErrorCorrect('M');

  handler.setQrcodeEncodeMode('B');

  handler.setQrcodeVersion(7);

  // System.out.println(content);

  byte[] contentBytes = content.getBytes("UTF-8");

  BufferedImage bufImg = new BufferedImage(140, 140, BufferedImage.TYPE_INT_RGB);

  Graphics2D gs = bufImg.createGraphics();

  gs.setBackground(Color.WHITE);

  gs.clearRect(0, 0, 140, 140);

  // 設定影像顏色:BLACK

  gs.setColor(Color.BLACK);

  // 設定偏移量 不設定肯能導致解析出錯

  int pixoff = 2;

  // 輸出內容:二維碼

  if (contentBytes.length > 0 && contentBytes.length < 124) {

  boolean[][] codeOut = handler.calQrcode(contentBytes);

  for (int i = 0; i < codeOut.length; i++) {

  for (int j = 0; j < codeOut.length; j++) {

  if (codeOut[j][i]) {

  gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);

  }

  }

  }

  } else {

  System.err.println("QRCode content bytes length = " + contentBytes.length + " not in [ 0,120 ]. ");

  }

  gs.dispose();

  bufImg.flush();

  // 生成二維碼QRCode圖片

  ImageIO.write(bufImg, "jpg", response.getOutputStream());

  } catch (Exception e) {

  e.printStackTrace();

  }

  }

  ——————————————————————————————

  // 位元組長度須控制在124個長度以內,否則報異常陣列索引值溢位

  String content = localIp + ":" + port + path + "/upload/toUploadMain.html?" + params;

  EncoderHandler encoder = new EncoderHandler();

  encoder.encoderQRCoder(content, response);

  所以content字串拼接時,注意長度不得超出124個位元組,否則報錯,如下圖所示:

  wKiom1g2VqTixbBzAAQALYELuVs862.jpg

  恩,以上內容即為今天要講解的動態生成二維碼並上傳資源的所有知識點了,各位猿人們多動手操作幾次,相信你也能很好的學好一項小技術,如有任何疑問或建議的歡迎來博吐槽。

  附件資源無法下載情況下,請自行挪步連結:

  如果各位童鞋還有任何建議或比較好的想法,歡迎加入JAVA開發專案討論群:214404624。

  發揮你聰智的大腦,挖掘更新鮮更充滿活力的好點子,我們共同探討技術層面的研究和可實施性。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69920892/viewspace-2723124/,如需轉載,請註明出處,否則將追究法律責任。

相關文章