亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue、SprinBoot開發運維的一些坑和知識集錦

發布時間:2020-03-03 14:11:43 來源:網絡 閱讀:771 作者:BlueMiaomiao 欄目:web開發

一、完美解決Vue2.0+Axios開發生產環境跨域問題

由于博主主要是做后端開發和自動化運維的,因此,前端基本面向同學和搜索引擎編程...這次徹底搞出了一個簡潔優雅的Vue和Axios配合的跨域方案,適合開發環境和生產環境!

(1)在config/index.js中配置開發環境跨域

proxyTable: {
    '/api': {
        target: 'https://211.64.32.228:8899/',
        secure: false,
        changeOrigin: true,
        pathRewrite: {
            '^/api': ''
        },
        headers: {
            Referer: 'https://211.64.32.228:8899'
        }
    }
}

(2)在main.js中配置自動選擇

import axios from 'axios'
import QS from 'qs'

Vue.prototype.$axios = axios
Vue.prototype.$qs = QS

Vue.prototype.baseUrl = process.env.NODE_ENV === "production" ? "https://211.64.32.228:8899" : "/api"

(3)在Vue文件中使用Axios

this.axios({
    method: 'post',
    url: this.baseUrl + '/helloworld',
    data: {},
    headers: {}
}).then((response) => {
    // do some
}).catch((error) => {
    // do some
});

(4)SpringBoot配置允許跨域

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }
}

二、SpringBoot中AES+Base64加解密用戶登錄憑據

這年頭,md5是能反解的,再老也不能掉牙呀..

import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

// 使用方法:
// PasswordUtil.Encrypt(String)
// PasswordUtil.Decrypt(String)
public class PasswordUtil {

    // openssl rand -hex 16
    private static String salt = "38350e78e96b83e894b59cc9953af122";

    public static String Encrypt(String password) throws Exception {
        byte[] raw = salt.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec sRawSpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, sRawSpec);
        byte[] encrypted = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
        return new Base64().encodeToString(encrypted);
    }

    public static String Decrypt(String password) throws Exception{
        byte[] raw = salt.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec sRawSpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, sRawSpec);
        byte[] encrypted = new Base64().decode(password);
        byte[] original = cipher.doFinal(encrypted);
        return new String(original, StandardCharsets.UTF_8);
    }
}

三、純CSS自定義超簡潔文件上傳控件input

主要是解決自定義CSS樣式問題和Vue上傳文件的問題...注釋就不寫了,靜下心來稍微一看就懂!

<template>
  <div class="upload">
    <div class="upload-demo-show">
      <input accept="image/png,image/gif,image/jpeg" type="file" class="upload-demo-button" @change="handleUploadDemoButtonChange($event)">
      <i class="el-icon-upload upload-btn-icon" :></i>
      <div class="upload-demo-text" :>{{uploadTips}}</div>
    </div>
    <div class="upload-button">
      <el-button :loading="isProcessUpload" type="success" icon="el-icon-right" circle @click="handleProcessUpload"></el-button>
    </div>
  </div>
</template>

<script>
    export default {
        name: "Upload",
        data: function () {
            return {
                uploadImageObject: '',
                isProcessUpload: false,
                uploadTips: '點擊上傳',
                uploadTipsStyle: {
                    'color': 'gray'
                }
            }
        },
        mounted() {
            this.$store.dispatch('commitNormalStepNumber', 2)
        },
        methods: {
            handleUploadDemoButtonChange: function (e) {
                if ((e.target.files[0].size / 1024) >= 400) {
                    this.$message.error('上傳的文件超過指定的大小, 請重新選擇');
                } else {
                    this.uploadImageObject = e.target.files[0];
                    this.uploadTips = e.target.files[0].name;
                    this.uploadTipsStyle.color = '#409EFF';
                }

            },
            handleProcessUpload: function () {

                this.isProcessUpload = true;

                // 使用FormData解決POST遠程API出現獲取不到參數問題
                let formData = new FormData();
                formData.append('uuid', this.$store.getters.getFormUsername);
                formData.append('file', this.uploadImageObject);

                this.$axios({
                    url: this.baseUrl + '/upload/image',
                    method: 'post',
                    headers: {
                        'Content-Type': 'multipart/form-data',
                        token: this.$store.getters.getToken
                    },
                    data: formData
                }).then((response) => {
                    if (response.data === "OK") {
                        this.isProcessUpload = false;
                        this.$router.push({
                            path: '/finish'
                        });
                    } else if (response.data === "UNAUTHORIZED"){
                        this.$message.error('請登錄后重試');
                    } else if (response.data === "INTERNAL_SERVER_ERROR") {
                        this.$message.error('很抱歉, 我們發生了一些錯誤');
                    } else if (response.data === "BAD_REQUEST") {
                        this.$message.error('你的請求有誤, 文件可能有點兒問題');
                    } else {
                        this.$message.error('產生了無法預知的錯誤, 請重新登陸');
                        console.log(response.data)
                    }
                }).catch((err) => {
                    this.$message.error('網絡請求出錯');
                    console.log(err)
                });

                this.isProcessUpload = false;
            }
        }
    }
</script>

<style scoped>
  .upload {
    width: 50%;
    margin: 0 auto;
    padding-top: 35px;
  }

  .upload-button {
    padding-top: 25px;
    text-align: center;
  }

  .upload-demo-button {
    width: 349px;
    height: 149px;
    opacity: 0;
  }

  .upload-demo-button:hover {
    cursor: pointer;
  }

  .upload-demo-show {
    border-radius: 5px;
    border: lightgray 1px dashed;
    width: 350px;
    height: 150px;
    margin: 0 auto;
    position: relative;
  }

  .upload-btn-icon {
    position: absolute;
    top: 15%;
    left: 40%;
    font-size: 50pt;
    z-index: -1;
  }

  .upload-demo-text {
    z-index: -1;
    position: absolute;
    top: 58%;
    width: 250px;
    text-align: center;
    left: 50%;
    font-size: 10pt;
    margin-left: -125px;
  }
</style>

四、Vuex最佳實踐

(1)定義store/index.js,事實上應該事先模塊化,但是我太懶了。

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const state = {
  token: ''
};

const getters = {
  getToken(state) {
    return state.token
  }
};

const mutations = {
  setToken(state, token) {
    state.token = token
  }
};

const actions = {
  commitToken({commit}, token) {
    return commit('setToken', token)
  }
};

const store = new Vuex.Store(
  {
    state,
    getters,
    mutations,
    actions
  }
);

export default store;

(2)在main.js中引用

import store from './store'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: {App},
  template: '<App/>',
  store
})

(3)在Vue組件中引用

this.$store.dispatch('commitToken', value);  // 向Store中存儲數據
this.$store.getters.getToken;                // 讀取Store中的數據

五、Vue-router跳轉

然而,官方文檔是寫的很明確的,但是我懶得翻官方文檔...

this.$router.push({
    path: '/normal'
});

六、Nginx配合SpringBoot實現HTTPS強轉和API網關負載均衡

user  nginx;
worker_processes  16;

error_log  logs/error.log;

pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    gzip  on;

    // 設置反向代理
    upstream apiserver {
        server 127.0.0.1:8090 weight=1;
        server 127.0.0.1:8091 weight=1;
        server 127.0.0.1:8092 weight=1;
        server 127.0.0.1:8093 weight=1;
    }

    server {
        listen       80;
        server_name  upload-image;

        // 設置HTTPS強轉
        rewrite ^(.*)$ https://$host$1 permanent;
    }

    // API接口使用HTTPS
    server {
        listen       8899 ssl;
        server_name  upload-image-api;

        // 配置HTTPS
        ssl_certificate      ../ssl/server.crt;
        ssl_certificate_key  ../ssl/server.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers ALL:!DH:!EXPORT:!RC4:+HIGH:+MEDIUM:-LOW:!aNULL:!eNULL;
        ssl_prefer_server_ciphers  on;

        // 添加支持的HTTPS協議
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

        location / {
            proxy_pass http://apiserver;
        }
    }

    server {
        // 將前端靜態分發設置跳轉到該接口
        listen       443 ssl;
        server_name  upload-image-ssl;

        ssl_certificate      ../ssl/server.crt;
        ssl_certificate_key  ../ssl/server.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers ALL:!DH:!EXPORT:!RC4:+HIGH:+MEDIUM:-LOW:!aNULL:!eNULL;
        ssl_prefer_server_ciphers  on;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

        location / {
            root   html;
            index  index.html index.htm;    
        }

        error_page  404              /404.html;
        error_page   500 502 503 504  /50x.html;

        location = /50x.html {
            root   html;
        }
    }

}

七、Vue組件水平垂直都居中

就是這個問題,我一直都記不住怎么做,但是我一直都能百度到,連Google都不用...

(1) index.html,設置在style標簽

html, body {
    margin: 0;
    padding: 0;
}

(2) 組件樣式

.box {
    top: 50%;
    left: 50%;
    position: absolute;
    transform: translate(-50%, -50%);
    min-width: 450px;
    max-width: 550px;
    min-height: 500px;
    max-height: 550px;
}

八、Vue與PC端攝像頭交互

最近自己用Caffe訓練了一個人臉識別的神經網絡,以后咱也可以人臉登錄了~
So,先搞定PC的Web端的攝像頭再說...因為電腦拍出來的照片是不太順眼的,因此進行了鏡像翻轉,
但是,你就是那么丑...是我的CSS讓你變好看了,哈哈哈~

<template>
  <div class="login-with-facedetection-main box">
    <div class="login-with-facedetection-main-head">
      <img src="../../assets/qimo2-blue.svg" alt="" width="65" height="65">
    </div>
    <div class="login-with-title">青芒云(Qimo Cloud)控制臺</div>
    <div class="login-with-subtitle">人臉檢測登錄,點擊圖片開始檢測</div>
    <div ></div>
    <div class="login-with-form" @click="handleFaceDetection" v-loading="hasLoginFormLoading">
      <video class="video-box" src="" autoplay="autoplay" v-if="hasCameraOpen"></video>
      <img class="photo-box" :src="faceImage" alt="" v-if="hasTakePhoto">
      <canvas id="canvas" width="270" height="270" ></canvas>
    </div>
    <LoginType/>
  </div>
</template>

<script>
    import LoginType from "../common/LoginType";

    export default {
        name: "LoginWithFaceDetection",
        components: {LoginType},
        data: function () {
            return {
                streamPicture: '',
                faceImage: '',
                hasCameraOpen: true,
                hasTakePhoto: false,
                faceImageFile: '',
                hasLoginFormLoading: false,
                clickTimes: 0
            }
        },
        methods: {
            handleFaceDetection: function () {
                if (this.clickTimes === 0) {
                    let video = document.querySelector('video');
                    this.takePhoto();
                    this.closeCamera();
                    this.postFaceDetection();
                    console.log("Face De");
                    this.clickTimes = 1;
                }
                // TODO:顯示彈窗,重復的提交
            },
            connectToCamera: function () {
                let self = this;
                navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
                if (navigator.getUserMedia) {
                    // 調用用戶媒體設備, 訪問攝像頭
                    navigator.getUserMedia({
                        video: {
                            width: 270,
                            height: 270
                        }
                    }, function (stream) {
                        let video = document.querySelector('video');
                        video.srcObject = stream;
                        self.streamPicture = stream;
                        video.onloadedmetadata = function (e) {
                            video.play();
                        };
                    }, function (err) {
                        // TODO: 顯示錯誤彈窗,不支持的媒體類型
                    })
                } else {
                    // TODO:顯示錯誤彈窗,無法訪問攝像頭
                }
            },
            closeCamera: function () {
                this.streamPicture.getTracks()[0].stop();
            },
            takePhoto: function () {
                let video = document.querySelector('video');
                let canvas = document.getElementById('canvas');
                let context = canvas.getContext('2d');
                context.drawImage(video, 0, 0, 270, 270);
                let image = canvas.toDataURL('image/png');
                this.hasCameraOpen = false;
                this.hasTakePhoto = true;
                this.faceImage = image;
                this.faceImageFile = this.dataURLtoFile(image, 'face-detection.png')
            },
            dataURLtoFile: function (dataurl, filename) {
                let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
                    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
                while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                }
                return new File([u8arr], filename, {type: mime});
            },
            postFaceDetection: function () {
                this.hasLoginFormLoading = true;

                // TODO:發送圖片進行識別

                setInterval(() => {
                    this.hasLoginFormLoading = false;
                    clearInterval();
                }, 5000);
            }
        },
        mounted() {
            this.connectToCamera();
        },
        destroyed() {
            this.closeCamera();
        }
    }
</script>

<style scoped>

  .photo-box {
    margin-top: 0;
    width: 270px;
    height: 270px;
    border-radius: 20px;
    transform: rotateY(180deg);
    -webkit-transform: rotateY(180deg); /* Safari 和 Chrome */
    -moz-transform: rotateY(180deg);
  }

  .video-box {
    transform: rotateY(180deg);
    -webkit-transform: rotateY(180deg); /* Safari 和 Chrome */
    -moz-transform: rotateY(180deg);
    margin-top: 0;
    width: 270px;
    height: 270px;
    object-fit: contain;
    border-radius: 20px;
  }

  .login-with-facedetection-main {
    width: 450px;
    height: 500px;
    box-shadow: 0 0 10px lightgrey;
  }

  .login-with-facedetection-main-head {
    width: 100%;
    height: 65px;
    padding-top: 35px;
    text-align: center;
  }

  .login-with-form {
    width: 270px;
    margin: 0 auto;
    height: 270px;
    text-align: center;
    background-color: #F1F3F4;
    border-radius: 20px;
  }

  .login-with-title {
    font-size: 15pt;
    text-align: center;
    width: 100%;
    padding-top: 20px;
  }

  .login-with-subtitle {
    font-size: 11pt;
    text-align: center;
    width: 100%;
    padding-top: 5px;
  }

  .box {
    top: 50%;
    left: 50%;
    position: absolute;
    transform: translate(-50%, -50%);
    min-width: 450px;
    max-width: 550px;
    min-height: 500px;
    max-height: 550px;
  }
</style>

九、Vue中組價高度自適應

讓這個組件的高度總是等于瀏覽器窗口高度!

(1)組件綁定CSS樣式

:

(2) JavaScript數據動態綁定

export default {
    name: "Admin",
    data: function () {
        return {
            isCollapse: true,
            sidebarStyle: {
                'height': ''
            }
        }
    },
    methods: {
        redressHeight: function () {
            this.sidebarStyle.height = window.innerHeight  + 'px';
        }
    },
    created() {
        window.addEventListener('resize', this.redressHeight);
        this.redressHeight();
    },
    destroyed() {
        window.removeEventListener('resize', this.redressHeight);
    }
}

持續更新中...

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

清河县| 嘉鱼县| 中卫市| 鸡西市| 抚远县| 巴林右旗| 江都市| 分宜县| 安平县| 麻栗坡县| 上饶市| 鹿泉市| 抚松县| 石门县| 麟游县| 石河子市| 繁昌县| 尤溪县| 崇左市| 黄大仙区| 厦门市| 义乌市| 伊金霍洛旗| 瑞安市| 灵璧县| 根河市| 新源县| 龙川县| 夏津县| 垣曲县| 周至县| 昆明市| 苍山县| 应用必备| 和政县| 文登市| 宣化县| 龙州县| 凉山| 沂水县| 来宾市|