精华内容
下载资源
问答
  • 微信小程序+Java后台开发(详细解释,附代码)

    万次阅读 多人点赞 2019-02-18 12:59:54
    微信小程序+Java后台开发 全部代码链接 链接:https://pan.baidu.com/s/1GiIXKgu76Urr7QfZ-U7W9A 提取码:mpio 通过这个博客,你可以快速的搭建一个微信小程序前端和后台相连的一个功能,在这里我会详细的解说每一...

    微信小程序+Java后台开发

    全部代码链接

    若失效,关注我的公众号回复关键字【666】点击领取
    迈莫公众号

    • 通过这个博客,你可以快速的搭建一个微信小程序前端和后台相连的一个功能,在这里我会详细的解说每一个步骤,就是如何实现小程序的前后台相互关联;因为是实现简易的小程序的某个功能,主要是为了了解小程序前台如何和后台相连,所以在此博客中使用的是本地tomcat服务器。*

    使用的工具:

    idea
    springmvc
    微信小程序开发工具
    tomcat
    微信小程序API
    所使用的jar包
    我已经上传到百度云盘里了,如果有需要可以去下载
    链接:https://pan.baidu.com/s/1KSqQLs9JMWB2SqgVVEwhKw
    提取码:9s0s
    在这里插入图片描述
    1.JAV后端详解

    我写后台主要使用的是Java,框架是SSM,由于自己的知识浅薄,只能使用自己已有的知识进行开发学习,因为微信小程序前台和后台数据传输是以Json数据格式传送的,所以建议如果了解过springBoot的话,用它更加方便快捷。

    在这里我给大家说一个json数据格式究竟是什么,希望对大家有点帮助!!!

    1. json数据格式
      2.1 jso有两种格式:一个是json对象,另一种是json数组
      2.1.1 json对象:可以理解为Java中对象,是以键值对形式存在的
      例子: {“key”:value, “key1”:value1}
      2.1.2 json数组:
      例子:[{“key”:value,“key”:value}]

    首先在idea中创建一个JavaEE项目,具体如何创建,在这里我就不祥解了,如果有不会的,可以去网上搜一艘,在这里我会直接打开我先前创建下个JavaEE项目。

    1. 首先在微信小程序开发工具中新建一个项目,然后再自己所写的某一个页面中,其次在自己页面的wxml文件中编写内容
      web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
        <!--前端控制器-->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        <!--字符编码-->
        <filter>
            <filter-name>encoding</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>utf-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    
    1. 其次在src/springmvc.xml编写springMVC的配置文件
      springMVC.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
             http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd"
           default-autowire="byName">
    
        <!--注解扫描-->
        <context:component-scan base-package="com.zb.lq.controller"/>
        <!--注解驱动-->
        <mvc:annotation-driven></mvc:annotation-driven>
    </beans>
    
    1. 然后在控制器中编写代码
      我的实在DemoController中编写的
      在这里插入图迭代的片描述
      DemoController.java
    @Controller
    public class DemoController {
        @RequestMapping("getUser")
        @ResponseBody
        public List<String> getUser(){
            List<String> list = new ArrayList<>();
            list.add("中北大学");
            list.add("653");
            list.add("实验室");
            return list;
        }
    }
    

    至此,使用Java编写的后台已经基本完成,接下来启动tomcat,测试看是否编写成功
    如果出现一下内容,则说明后台编写成功,要以json格式输出,因为小程序前台和后台相连是以json格式输出的

    在这里插入图片描述

    1. 我以简单的按钮实现前后台交互:
      index.wxml
    <button bindtap='houduanRequest'>获取信息</button>
    <view wx:for="{{list}}" wx:fot-item="item">
      姓名:{{item}}
    </view>
    

    index.js

    //index.js
    const app = getApp()
    
    Page({
      data: {
        list:''
      },
      houduanRequest:function(){
        var that = this;
        wx.request({
          url: 'http://localhost:8888/xiaochengxu/getUser',//自己请求的服务器的地址
          method: 'GET',
          header: {
            'content-type': 'application/json' // 默认值
          },
          success: function (req) {
            var list = req.data;
            if (list == null) {
              wx.showToast({
                title: 'ErrorMessage',
                icon: 'false',   //图标
                duration: 1500  //提示的延迟的时间
              })
            } else {
              that.setData({
                list: list
              })
            }
          }
        })
      },
    
      onLoad: function() {
        
      }, 
    
    })
    
    

    到此基本的功能代码已经完成了,现在我们开始启动tomcat,进行运行,看看结果究竟是什么…

    在这里插入图片描述

    在这里插入图片描述到此,实现小程序前后台相连已经实现了
    希望对大家有点帮助!!!

    公众号

    希望大家多多关注,里面不定期发放干货
    领取全套资料:回复关键字【666】
    迈莫公众号

    展开全文
  • 我的C++后台开发学习路线(秋招,C++后台,面经)

    万次阅读 多人点赞 2018-11-27 10:08:01
    后台开发包括的知识点很多,包括语言基础,算法,linux编程基础,linux内核,网络,数据库,分布式等等。面面俱到很难,一个领域钻研的很深也很难。我认识的大神里有把C++语言吃的非常透的,也有实验室就是搞分布式...

    后台开发包括的知识点很多,包括语言基础,算法,linux编程基础,linux内核,网络,数据库,分布式等等。面面俱到很难,一个领域钻研的很深也很难。我认识的大神里有把C++语言吃的非常透的,也有实验室就是搞分布式的,拿offer都非常轻松。



    我在本次秋招拿到了:

    字节跳动后台开发ssp
    网易游戏游戏研发ssp
    阿里云基础平台开发
    华为15级顶薪
    腾讯后台开发ssp

    我准备应聘的时间从研一的寒假开始,当然自己探索的路上走了不少弯路。

    列举一下自己的学习内容中我自己认为对找工作或者对提升自己非常有帮助的一些书或资料,仅供参考~


    语言基础,C++语言相关的:

    《C++ Primer》,应该算是工具书,但我花了3个月一个字一个字啃完了,现在能记住的没几个了,但是好在全看完就不用看Effective C++了,基本都包含在内了。

    《STL源码剖析》,很老的书了,很多内容都过时来了,比如空间配置器,但是面试官还是会问……可以跟面试官讲讲ptmalloc的实现。整本书都是重点。

    《深度探索C++对象模型》,虽然基本只会问虚函数的实现,看一篇博客也能应付面试,但是还是建议多看几遍。

    《Effective C++:改善程序与设计的55个具体做法》还有more effective C++,建议快速看一下。

    STL和对象模型我都看了3遍以上,因为太容易忘了,Effective C++只是快速浏览了一遍,发现基本都包含在Primer里了。



    网络,除了本科学过的(《计算机网络 自顶向下方法》),我看了《TCP/IP详解卷1》12-16章,重点是TCP、IP、UDP,其它部分看书太麻烦了,直接从博客里看了。



    linux环境编程apue和unp两本是必须的,因为太厚了,看起来还是有点痛苦的,但是不需要全看,而且内容重叠很多。unp卷1前面8章是重点,卷2前面4部分都挺重要的,apue全部,先是要有个概念,自己写代码的时候就知道哪块重要了。


    此外,《后台开发:核心技术与应用实践》是腾讯的员工写的,虽然这本书评价比较差,几乎都是抄的博客,但是内容上总结的很好(我觉得就是给校招的同学写的),都是后台开发需要的基础知识的总结,这本书中内容所代表的知识,基本都是腾讯的C++后台开发工程师所必备的基础,可以作为一个复习提纲。

     

    下面的书应该算是提高篇了:


    linux内核相关,我买了《深入理解linux内核》发现啃不动,后来看了《linux内核设计与实现》,非常推荐,外加一大堆博客,《深入理解计算机系统》讲的东西比较简单,这个可以作为一个补充,面试官问的很多操作系统相关的问题书中都有涉及。


    《Linux多线程服务器端编程》,陈硕的书,讲muduo网络库的,我看了3.4遍,源码也读了3.4遍,收获非常多。前面部分是后台开发的一些经验之谈,对面试也很有用。

    《Redis设计与实现》看完感觉也特别好,很值得学习,可以很快就看完。有很多重要的数据结构可以在面试的时候讲出来,比如跳表、redis的 hash表啦~

    《深入理解Nginx》我也看了一部分,nginx太经典了,很多面试官也都提到过。

    短小精悍的源码还非常推荐leveldb,对照博客把leveldb源码看完不需要多长时间(我花了两个周吧),但是收获非常多。在此基础上还可以了解一下rocksdb。

    除此之外,还看过一些其它的书,感觉不值得推荐就不写了。



    书是比较系统性的东西,博客通常是总结性的东西,也是对书中内容的一个补充吧。好多东西面试会问到,但是书中很难找到解答,对照着网上的面经搜博客吧。我看了下自己收藏夹里的光是收藏的博客就已经上百篇了,当然还是不能完全覆盖面试官会问到的问题。(这一步是重点啊)

    分享一下我自己看过的博客,从手机书签里导出来的,整理了一下:

    http://www.linya.pub/



    算法

    我只刷了Leetcode上的500多题,但是第一遍不会的题都标记了,后面又刷了很多遍。《剑指offer》这种书不太建议看,很啰嗦,解答也不如LeetCode上的高票解答。直接干刷其实还有点无聊的,每周日上午做一下leetcode的周赛也是个不错的选择,可以当做模拟笔试/面试。另外 Top 100 Liked Questions 可以重点关注一下。



    项目

    https://github.com/linyacool/WebServer

    写了一个静态Web服务器,主要是找实习的时候用的,参考了muduo网络库。

     

    阿里云校招(实习)内推,可以发送简历至linya.ly@alibaba-inc.com,有hc,也可以微信和我联系,咨询相关问题,微信linyacool

    展开全文
  • 3小时入门后台开发与服务器部署

    千人学习 2019-09-23 13:47:14
    想了解后台开发的app移动端开发人员 想了解后台开发的web前端同学 在校大学生 创业人员 这套课程全部是用大白话讲解,即便你是一个编程小白,没有任何开发经验,只要跟着视频,一步步来,你...
  • app后台开发入门

    万次阅读 多人点赞 2017-04-20 16:35:59
    前言:由于项目需求,我负责安卓后台开发这部分内容。服务器收到安卓的请求后,返回json数据给安卓用。 但是,我什么都不懂啊!我不知道安卓后台服务器长什么样子,我见都没见过,怎么开发?怎么照猫画虎!!! ...

    2017/5/1第二次更新

    前言:

    在我写下这篇文章之前,我头脑中的app后台开发,有且只有一个流程“客户端Cilent向服务器Server请求数据,服务器Server响应客户端请求并返回json数据”。但是,仅仅用语言描述出这个流程,对开发没有任何实质性的帮助。

    所以不夸张的说,对于app后天开发,我完完全全是零基础。小白小白还是小白。

    我是小白,这点毋庸置疑,但是只要对一些概念有一定的了解,后台开发还是有戏的。

    1: 提前做好刻苦学习的心理准备。因为后台开发的细节确实很多!


    正文:

    下面我罗列几个当初困扰我的问题,虽然有的现在看来不必要,但是难免其他人会问到。所以就留在那里,不打算删掉。

    • 问1:后台开发和服务器开发有什么区别和联系?
      答:对于新手,你可以认为他俩么有区别,是一个东西,区不区分清楚对你学习app后台开发没什么影响。
      这里写图片描述
      如果非要严谨点区分:
      这里写图片描述

    • 问2:http服务器,web服务器,应用服务器有什么区别?
      答:为什么叫http服务器呢?是因为该服务器支持http协议,所以这样命名。就像支持ftp协议的叫ftp服务器。web服务器是指同时支持http,https,ftp等多种协议的服务器。web服务器支持多种协议,自然要比单一的http服务器要强大。对于初学者,是否区分清楚web服务器http服务器的区别,对开发过程基本没有影响。
      注释:(http服务器==web服务器)
      这里写图片描述
      更多web(http)服务器与应用服务器的关系

    • 问3:web后台开发和手机app后台开发(也就是服务器开发)有什么区别?
      答:不严谨的说,web后台开发和app后台开发有区别,但区别不大。
      这里写图片描述

    • 问4:app后台怎么开发
      《App后台开发运维和架构实践》作者主页链接
      《Android 和PHP 开发最佳实践》第二版
      就我个人来说,上面两本书作用不是很大,看看就行,先别着急买。

    • 问5:app后台开发教程
      android 后台开发简单教程

    • 问6:app后台开发路线
      这里写图片描述

    • 问7:app和服务器如何通讯?
      这里写图片描述

    • 问8:api如何调调试?
      百度在线api测试平台,浏览器api测试插件。

    • 问9:app后台开发长啥样子
      答:后台开发语言有很多,这里以PHP为例,通过代码简单介绍app后台基本原理
      安卓流程


    php处理请求返回json数据

    这里写图片描述

    php返回的json数据

    {
        "products": [
            {
                "pid": "1",
                "name": "iPhone 4S",
                "price": "300.00",
                "created_at": "2012-04-29 02:04:02",
                "updated_at": "0000-00-00 00:00:00"
            },
            {
                "pid": "2",
                "name": "Macbook Pro",
                "price": "600.00",
                "created_at": "2012-04-29 02:04:51",
                "updated_at": "0000-00-00 00:00:00"
            },
            {
                "pid": "3",
                "name": "Macbook Air",
                "price": "800.00",
                "created_at": "2012-04-29 02:05:57",
                "updated_at": "0000-00-00 00:00:00"
            },
            {
                "pid": "4",
                "name": "OS X Lion",
                "price": "100.00",
                "created_at": "2012-04-29 02:07:14",
                "updated_at": "0000-00-00 00:00:00"
            }
        ],
        "success": 1
    }

    app源码

    AllProductsActivity.java
    
    public class AllProductsActivity extends ListActivity {
    
        // Progress Dialog
        private ProgressDialog pDialog;
    
        // Creating JSON Parser object
        JSONParser jParser = new JSONParser();
    
        ArrayList<HashMap<String, String>> productsList;
    
        // url to get all products list
        //向服务器上的get_all_products.php发出请求,然后才能得到json数据
        private static String url_all_products = "http://api.androidhive.info/android_connect/get_all_products.php";
    
        // JSON Node names
        private static final String TAG_SUCCESS = "success";
        private static final String TAG_PRODUCTS = "products";
        private static final String TAG_PID = "pid";
        private static final String TAG_NAME = "name";
    
        // products JSONArray
        JSONArray products = null;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.all_products);
    
            // Hashmap for ListView
            productsList = new ArrayList<HashMap<String, String>>();
    
            // Loading products in Background Thread
            new LoadAllProducts().execute();
    
            // Get listview
            ListView lv = getListView();
    
            // on seleting single product
            // launching Edit Product Screen
            lv.setOnItemClickListener(new OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {
                    // getting values from selected ListItem
                    String pid = ((TextView) view.findViewById(R.id.pid)).getText()
                            .toString();
    
                    // Starting new intent
                    Intent in = new Intent(getApplicationContext(),
                            EditProductActivity.class);
                    // sending pid to next activity
                    in.putExtra(TAG_PID, pid);
    
                    // starting new activity and expecting some response back
                    startActivityForResult(in, 100);
                }
            });
    
        }
    
        // Response from Edit Product Activity
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            // if result code 100
            if (resultCode == 100) {
                // if result code 100 is received
                // means user edited/deleted product
                // reload this screen again
                Intent intent = getIntent();
                finish();
                startActivity(intent);
            }
    
        }
    
        /**
         * Background Async Task to Load all product by making HTTP Request
         * */
        class LoadAllProducts extends AsyncTask<String, String, String> {
    
            /**
             * Before starting background thread Show Progress Dialog
             * */
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                pDialog = new ProgressDialog(AllProductsActivity.this);
                pDialog.setMessage("Loading products. Please wait...");
                pDialog.setIndeterminate(false);
                pDialog.setCancelable(false);
                pDialog.show();
            }
    
            /**
             * getting All products from url
             * */
            protected String doInBackground(String... args) {
                // Building Parameters
                List<NameValuePair> params = new ArrayList<NameValuePair>();
                // getting JSON string from URL
                JSONObject json = jParser.makeHttpRequest(url_all_products, "GET", params);
    
                // Check your log cat for JSON reponse
                Log.d("All Products: ", json.toString());
    
                try {
                    // Checking for SUCCESS TAG
                    int success = json.getInt(TAG_SUCCESS);
    
                    if (success == 1) {
                        // products found
                        // Getting Array of Products
                        products = json.getJSONArray(TAG_PRODUCTS);
    
                        // looping through All Products
                        for (int i = 0; i < products.length(); i++) {
                            JSONObject c = products.getJSONObject(i);
    
                            // Storing each json item in variable
                            String id = c.getString(TAG_PID);
                            String name = c.getString(TAG_NAME);
    
                            // creating new HashMap
                            HashMap<String, String> map = new HashMap<String, String>();
    
                            // adding each child node to HashMap key => value
                            map.put(TAG_PID, id);
                            map.put(TAG_NAME, name);
    
                            // adding HashList to ArrayList
                            productsList.add(map);
                        }
                    } else {
                        // no products found
                        // Launch Add New product Activity
                        Intent i = new Intent(getApplicationContext(),
                                NewProductActivity.class);
                        // Closing all previous activities
                        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        startActivity(i);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
    
                return null;
            }
    
            /**
             * After completing background task Dismiss the progress dialog
             * **/
            protected void onPostExecute(String file_url) {
                // dismiss the dialog after getting all products
                pDialog.dismiss();
                // updating UI from Background Thread
                runOnUiThread(new Runnable() {
                    public void run() {
                        /**
                         * Updating parsed JSON data into ListView
                         * */
                        ListAdapter adapter = new SimpleAdapter(
                                AllProductsActivity.this, productsList,
                                R.layout.list_item, new String[] { TAG_PID,
                                        TAG_NAME},
                                new int[] { R.id.pid, R.id.name });
                        // updating listview
                        setListAdapter(adapter);
                    }
                });
    
            }
    
        }
    }

    app效果展示
    这里写图片描述

    展开全文
  • 微信小程序后台开发详解

    万次阅读 多人点赞 2018-06-18 03:54:20
    微信小程序后台开发 前言 开发环境 开发流程 项目整体结构 接口开发 项目部署 ip映射 Nginx反向代理 gunicorn+super多进程开启服务+进程监控 ssl证书 小程序常用功能 微信支付 生成二维码 推送消息 测试 黑盒...

    微信小程序后台开发

    前言

    • 微信小程序已经是家喻户晓了,最近和同学一起刚上线了一款应用校园懒人邦,感兴趣的朋友可以搜索一下,一款基于校园最后一百米的概念开发的快递&外卖配送平台,我是负责后台开发部分,这里给朋友们介绍下相关开发经验,开发框架和方式有很多,这里给大家介绍一些快捷高效的方法,大家少走弯路!

    开发环境

    • macOs 10.13.2
    • PyCharm 16.1
    • Python 2.7
    • vim 8.0

    开发流程

    项目整体结构

    • 我们先来看下项目整体结构:
      项目整体结构
    • pjt: 整个项目的代码文件
      • api: 项目的所有接口信息
      • conf: 项目所有的配置信息
      • dal/dao: 数据维护层,所有的操作数据库的逻辑都要经过这里
      • db: 第一版使用的自己设计的orm框架,第二版废弃了
      • images: 图片缓存区,缓存存二维码还有用户头像上传七牛云
      • impl: 接口功能实现
      • key: 各种加密文件,微信支付,ssl证书等
      • log: 日志文件,目前天级别生成最新的一份
      • model: 数据模型, 第一版已废弃
      • pjt_data: 第二版使用Django QuerySet的orm框架,比自己写的方便多了大力推荐,具体学习可以查看这里,内部代码就不当做demo展示了,哈哈!
      • test_demo: 写一些功能的测试类,方便线上调试

    接口开发

    • 整个接口开发使用的是Flask框架,Flask是Python编写的轻量级Web应用框架,用过的人都知道简单快捷, 马上花一分钟上手下:
    • 安装: sudo pip install flask
    • 一个简单的demo:
    from flask import Flask
    app = Flask(__name__)
    
    @app.route("/")
    def hi():
        return "hi!"
    
    if __name__ == "__main__":
        app.run()
    • 运行程序,浏览器输入, 可以看到页面返回了一个hi!,ok,这就可以了, 整个框架我们就搭建起来了,是不是很简单,后面我们来拓展一下!
    http://127.0.0.1:5000/
    • 详细的flask教程可以参考这里

    项目部署

    ip映射

    • 个人选择的服务器是阿里云,性能不错,这里假设咱们的阿里云的Ip是1.2.3.4,那么首先我们要在服务器上建立映射关系,当我访问http://1.2.3.4:5000/时,不仅是本地能访问,任何地方都行,这个很简单,只要你买了服务器,里面有一项配置你服务器的ip地址就行。

    Nginx反向代理

    • 现在我们可以使用http://1.2.3.4:5000/访问网站了,还缺少一些什么?当然,微信小程序是不允许接口暴露ip地址的,你必须要用自己的域名和自定义的接口名称,比如http://www.happypower.com/这样才行,当我访问这个网站时候,会先到阿里云服务器上做一下映射,确定我们的ip1.2.3.4,然后找到该Ip对应的服务器,之后怎么办? 我需要访问的是http://1.2.3.4:5000/这个啊,Nginx帮我们做了这个事,下面简单介绍下:
    • 安装:具体看这里
    • 安装完了之后咱们先配置下,详细配置可以参考这里,这里我简单说下我的配置,并给出具体demo:
    • 进入目录/etc/nginx,每人安装目录可能不同,找到nginx.conf文件,vim进行编辑,vim的操作如果不熟可以查看这里,不行可以先本地测好再到线上用,下面给出我配置的信息,大家可以仿造,应该是比较精简的:
    # For more information on configuration, see:
    #   * Official English Documentation: http://nginx.org/en/docs/
    #   * Official Russian Documentation: http://nginx.org/ru/docs/
    
    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log;
    pid /run/nginx.pid;
    
    # Load dynamic modules. See /usr/share/nginx/README.dynamic.
    include /usr/share/nginx/modules/*.conf;
    
    events {
        worker_connections 1024;
    }
    
    http {
        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  /var/log/nginx/access.log  main;
    
        sendfile            on;
        tcp_nopush          on;
        tcp_nodelay         on;
        keepalive_timeout   65;
        types_hash_max_size 2048;
    
        include             /etc/nginx/mime.types;
        default_type        application/octet-stream;
    
        # Load modular configuration files from the /etc/nginx/conf.d directory.
        # See http://nginx.org/en/docs/ngx_core_module.html#include
        # for more information.
        #include /etc/nginx/conf.d/*.conf;
    
        server {
            listen       80  default_server;
            listen       [::]:80 default_server;
            server_name  _;
            root         /usr/share/nginx/html;
    
            # Load configuration files for the default server block.
            include /etc/nginx/default.d/*.conf;
    
            location / {
            return 404;
            }
    
            error_page 404 /404.html;
                location = /40x.html {
            }
    
            error_page 500 502 503 504 /50x.html;
                location = /50x.html {
            }
        }
    
    # Settings for a TLS enabled server.
    #
    #    server {
    #        listen       443 ssl http2 default_server;
    #        listen       [::]:443 ssl http2 default_server;
    #        server_name  _;
    #        root         /usr/share/nginx/html;
    #
    #        ssl_certificate "/etc/pki/nginx/server.crt";
    #        ssl_certificate_key "/etc/pki/nginx/private/server.key";
    #        ssl_session_cache shared:SSL:1m;
    #        ssl_session_timeout  10m;
    #        ssl_ciphers HIGH:!aNULL:!MD5;
    #        ssl_prefer_server_ciphers on;
    #
    #        # Load configuration files for the default server block.
    #        include /etc/nginx/default.d/*.conf;
    #
    #        location / {
    #        }
    #
    #        error_page 404 /404.html;
    #            location = /40x.html {
    #        }
    #
    #        error_page 500 502 503 504 /50x.html;
    #            location = /50x.html {
    #        }
    #    }
    
    # 自己主要要写的就下面这个server
    server {
        # 443是https监听的端口,一般默认就好
        listen 443;
        # 自己接口的主域名,这就是当我们访问http://www.happypower.com时就会映射到这里
        server_name www.happypower.com;
        ssl on;
        # 这是默认主页,接口没有主页就注释掉了
        # root html;
        # index index.html index.htm;
        # 下面是阿里云下载的ssl证书,后面会说到ssl的配置,看不懂没关系
        ssl_certificate   ./xxx.pem;
        ssl_certificate_key  ./xxx.key;
        ssl_session_timeout 5m;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        location / {
        # 这里的意思是http://www.happypower.com会和http://0.0.0.0:8888做一个映射,这就解决了上面最开始说的那个问题了,这一步很关键!
        proxy_pass               http://0.0.0.0:8888;
        }
        # 日志文件路径,有人访问你的网站时都会留下印记,有的话最好,不配置其实也行。
        access_log                 /root/xxx/pjt/log/nginx.log;
    }
    }

    gunicorn+super多进程开启服务+进程监控

    • 这两个很简单,其实就是几条命令的事,主要说下作用:
      1 gunicorn 可以让你的后台服务多进程方式开启,经过测试可以提升一定的qps(每秒的请求数),简单来说一定程度上防止你的服务器崩掉.

      2 supervisor 的作用就是对你的进程进行监控,该框架提供了一个可视化界面,可以通过这个界面去开启,暂停和关闭你的服务进程,即使不动代码的人也能控制后台服务。

      3 具体配置没啥好讲的,学会几个命令就行具体推荐看这里

    ssl证书

    由于小程序需要的接口都是需要https的连接,所以咱们还需要ssl证书才行,这里我使用的是阿里云服务器,具体配置可以先参考这里,可能有点难懂,下面简单说下我的配置:

    1. 我选择的是单域名免费型 DV SSL,其实一般的应用来说,单域名足够了。
    2. 官网下载ssl证书,一般是xxx.key和xxx.pem两个文件,上面Nginx反向代理配置就需要用到这个,可以返回上面的nginx.conf文件进行查看!
    3. 管理证书,这个就是配置问题,官方文档写的很详细
    4. 配置成功后,可以使用https://127.0.0.1:5000/ 或者https://www.happypower.com来访问你的网站,然后返回hi!,当然,也有可能访问不了,一般就是配置问题,https其实也是在访问http,只是中间多了一个验证的过程,感兴趣的可以到这里学习下http和https的区别。
    5. ps.建议用什么服务器就用哪里的证书,腾讯云阿里云推荐,其他的真的难配,个人遇到了很多坑!

    小程序常用功能

    微信支付

    有些小程序涉及到微信支付的,就比如校园懒人邦,这个其实很头疼,做过就知道,难到不是很难,过程很繁琐,官方文档也很多坑,下面简单讲解下:

    1. 首先一定要注册公司,这个让运营或者产品的同学去做会好一些
    2. 一般来说支付都是单向的,也就是使用者对公司付款,如果是公司对使用者付款则需要9个月的申请时间才行,这个比较坑,当然,退款是不需要等的.
    3. 具体细节可以先看文档,这里面讲的还是非常清楚的,包括一些接口说明等.
    4. 这里我使用python写了个微信预支付的较为通用的类,大家改下参数拿去用就行,官方文档一个个试出来的,简直坑:
    class WeiXinPay(object):
        """微信支付,返回回客户端需要参数
        """
        def __init__(self, uu_id, open_id, spbill_create_ip, total_fee, out_trade_no):
            """
            :param total_fee: 订单金额
            :param spbill_create_ip: 客户端请求IP地址
            """
            self.params = {
                'appid': '小程序的appid',
                'attach': u'你的应用名称,我这里是(校园懒人邦)',
                'body': u'校园懒人邦-代取费',
                'mch_id': '商户id,你企业的id',
                'nonce_str': '给个随机数,一般md5一下就好,时间戳啊或者别的什么',
                'notify_url': 'http://www.happypower.com/result(这个就是通知地址,会异步返回信息给你),你写一个接口接收就行',
                'openid': open_id,
                'out_trade_no': out_trade_no,
                'spbill_create_ip': spbill_create_ip,
                'total_fee': str(total_fee),
                'trade_type': 'JSAPI'
            }
            # 官方给的接口
            self.url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'
            self.error = None
    
        def key_value_url(self, value):
            """将将键值对转为 key1=value1&key2=value2
            """
            key_az = sorted(value.keys())
            pair_array = []
            for k in key_az:
                v = value.get(k, '').strip()
                v = v.encode('utf8')
                k = k.encode('utf8')
                pair_array.append('%s=%s' % (k, v))
            tmp = '&'.join(pair_array)
            return tmp
    
        def get_sign(self, params):
            """生成sign
            """
            stringA = self.key_value_url(params)
            stringSignTemp = stringA + '&key=' + 'xxx' # APIKEY, API密钥,需要在商户后台设置
            sign = (md5(stringSignTemp).hexdigest()).upper()
            params['sign'] = sign
    
        def get_req_xml(self):
            """拼接XML
            """
            self.get_sign(self.params)
            xml = "<xml>"
            for k, v in self.params.items():
                v = v.encode('utf8')
                k = k.encode('utf8')
                xml += '<' + k + '>' + v + '</' + k + '>'
            xml += "</xml>"
            print xml
            return xml
    
        def get_prepay_id(self):
            """
            请求获取prepay_id
            """
            xml = self.get_req_xml()
            headers = {'Content-Type': 'application/xml'}
            r = requests.post(self.url, data=xml, headers=headers)
            re_xml = ElementTree.fromstring(r.text.encode('utf8'))
            xml_status = re_xml.getiterator('result_code')[0].text
            if xml_status != 'SUCCESS':
                self.error = u"连接微信出错啦!"
                logging.error(u"连接微信出错啦!")
                return
            prepay_id = re_xml.getiterator('prepay_id')[0].text
            self.params['package'] = 'prepay_id=%s' % prepay_id
            self.params['timestamp'] = str(int(time.time()))
    
        def re_finall(self):
            self.get_prepay_id()
            if self.error:
                return
    
            sign_again_params = {
                'appId': self.params['appid'],
                'timeStamp': self.params['timestamp'],
                'nonceStr': self.params['nonce_str'],
                'package': self.params['package'],
                'signType': 'MD5'
            }
            self.get_sign(sign_again_params)
            sign_again_params['paySign'] = sign_again_params['sign']
            sign_again_params['total_fee'] = self.params['total_fee']
            sign_again_params['notify_url'] = self.params['notify_url']
            sign_again_params.pop('appId')
            sign_again_params.pop('sign')
            return json.dumps(sign_again_params)

    5 这里最后返回的参数传给前台就能支付了,前台会拿到你的prepay_id,然后就能按照指定金额支付了。
    6 退款的话有些不同,首先也是具体先查看文档,下面我也写了一个较为通用的类,大家觉得文档麻烦直接用也行:

    class WeiXinReturn(object):
        def __init__(self, out_trade_no, total_fee, refund_fee):
            self.params_mach = {
                # 申请商户号的appid或商户号绑定的appid
                'appid': 'xxx',
                'mch_id': 'xxx',
                'nonce_str': '随机数',
                'out_trade_no': out_trade_no,
                'out_refund_no': '微信订单号',
                'total_fee': str(total_fee),
                'refund_fee': str(refund_fee),
                'notify_url': 'http://www.happypower.com/pay_return/result(和支付一样的意思,就是退款的通知地址,自己开发一个接口就好)'
            }
    
        def pay_return(self):
            stringA = self.key_value_url(self.params_mach)
            stringSignTemp = stringA + '&key=' + 'xxx'  # APIKEY, API密钥,需要在商户后台设置
            sign = (md5(stringSignTemp).hexdigest()).upper()
            self.params_mach['sign'] = sign
            xml = "<xml>"
            for k, v in self.params_mach.items():
                v = v.encode('utf8')
                k = k.encode('utf8')
                xml += '<' + k + '>' + v + '</' + k + '>'
            xml += "</xml>"
            headers = {'Content-Type': 'application/xml;charset=UTF-8'}
            # url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'
            url = 'https://api.mch.weixin.qq.com/secapi/pay/refund'
            # 请求中需要带有支付的证书,没有证书是无法申请的
            r = requests.post(url, data=xml, headers=headers, cert=('xxx.pem', 'xxx.pem'))
            result = r.text
            re_xml = ElementTree.fromstring(r.text.encode('utf8'))
            xml_status = re_xml.getiterator('result_code')[0].text
            if xml_status == 'SUCCESS':
                return True
            return False
    
        def key_value_url(self, value):
            """将将键值对转为 key1=value1&key2=value2
            """
            key_az = sorted(value.keys())
            pair_array = []
            for k in key_az:
                v = value.get(k, '').strip()
                v = v.encode('utf8')
                k = k.encode('utf8')
                pair_array.append('%s=%s' % (k, v))
            tmp = '&'.join(pair_array)
            return tmp

    ps.这里需要商户证书,具体怎么弄看这里

    生成二维码

    • 这个功能比较常见了,同样也是先看文档,里面有三种二维码接口,开发阶段建议使用接口B:https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN, 项目上线了用接口A会更加灵活,因为可以通过二维码跳转页面且能够携带参数校园懒人邦中的分享功能就是利用接口A进行开发,主要接口A上线才好测,而接口B开发阶段好测。
    • 二维码是图片,涉及到存储问题,这里推荐七牛云,账号免费有10G的使用空间,很棒的,具体思路就是先到本地做一层缓存,然后本地上传到七牛云,相关代码可以参考下面的,基本已经封装好了:
        def upload_img(self, local_path, upload_name, bucket_name, ttl=7200):
            """
            上传图片到七牛云
            :param local_path: 本地文件路径
            :param upload_name: 上传文件名
            :param bucket_name: 七牛申请的存储空间名称
            :param ttl: 过期时间
            :return: 返回图片地址
            """
            from qiniu import Auth, put_file
            import re
            q = Auth(access_key=conf_test.AccessKey, secret_key=conf_test.SecretKey)
            token = q.upload_token(bucket_name, upload_name, ttl)
            ret, info = put_file(token, upload_name, local_path)
            pat_status = 'status_code:(.*?),'
            status_code = re.compile(pat_status, re.S).findall(str(info))
            if len(status_code) > 0:
                # 成功返回图片外链名称,失败返回原因以及状态码
                if int(status_code[0]) == 200:
                    return {"msg":conf_test.qiniu_domain + upload_name, "status":1}
            return {"msg":"failed upload img failed", "status":-1}
    • 相关的sdk文档可以参考这里
    • 还有一个问题就是微信小程序只能识别https的图片外链地址,而刚开始上传七牛云生成的是http的链接图片,因此这里需要到七牛云上面配置下,具体的可以查看这里
    • 二维码基本流程就是这么一套,当然缓存怎么做方式很多,这里仅供参考。

    推送消息

    • 给用户发送模板消息,提醒用户做一些事也是经常用到的功能,具体操作还是先查看文档,当然,微信规定了每天用户只能最多收到三条消息,当然还是有别的办法可以给用户多发一些消息,具体往下看.
    • 看文档可以知道,其实只需要有足够的用户form_id咱们就能对用户无限制的发送消息,前提是用户没有屏蔽你的这个微信小程序,可以参考这里,当然这里是用java写的,我按照这个封装了一个python版本的,大家可以参考着用:
        # 刷新用户form_id 存入redis
        def fresh_formid(self, **kwargs):
            """
            接收前台传来的form_id存入redis
            :param kwargs: 
            :return: 
            """
           uu_id = kwargs.get("uu_id", "")
           if not uu_id:
               return "failed: uu_id cannot be null"
           open_id = kwargs.get("open_id", "")
           if not open_id:
               return "failed: open_id cannot be null"
           form_id = kwargs.get("form_id", "")
           if not form_id:
               return "failed: form_id cannot be null"
           if "invalid code" in open_id:
               return "failed: get openid err"
           msg = {open_id: form_id}
           self.redis_cli.sadd(uu_id, json.dumps(msg))
           return "success"
        # 发消息模板
        def send_template_msg(self, **kwargs):
            uu_id = kwargs.get("uu_id", "")
            if not uu_id:
                return "failed: uu_id cannot be null"
            data = kwargs.get("data", "")
            if not data:
                return "failed: data can not be null"
            # 这个token可以从文档中去查看怎么得到,内部源码不能提供
            token = self.get_refresh_token()
            if not token:
                return "failed: cannot find a token"
            send_msg = {}
            # 从redis中取出用户对应的form_id
            redis_msg = self.redis_cli.spop(uu_id)
            if not redis_msg:
                return "failed: cannot find a open_id in redis"
            msg = json.loads(redis_msg.encode("utf8"))
            touser = msg.keys()[0]
            form_id = msg[touser]
            template_id = kwargs.get("template_id", "")
            if not template_id:
                return "failed: template_id cannot be null"
            # page是用户点开消息后跳转到的页面
            page = kwargs.get("page", "")
            # 下面这些参数的含义在文档中都能查到
            emphasis_keyword = kwargs.get("emphasis_keyword", "")
            send_msg["touser"] = touser
            send_msg["template_id"] = template_id
            send_msg["page"] = page
            send_msg["form_id"] = form_id
            send_msg["data"] = data
            send_msg["emphasis_keyword"] = emphasis_keyword
            # 调起发送消息接口
            api = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=%s" % token
            # post方式发起网络请求
            return self.get_html(url=api, data=send_msg)

    测试

    黑盒测试

    • 应用上线之前肯定要各种测试才行,功能上黑盒测试可以交给不太懂代码的同学,也就是按照流程走通一遍,中途出现的问题记录下来然后交给程序哥哥。

    qps测试

    • 我这里主要介绍下qps的测试,因为我们是给用户用的,我们必须估计一下我们的服务器能承载多少用户同时在线,也就是平均来说能承受多少用户每秒的请求数量, 我们可以对最常用的几个接口做一个极限测试,然后计算出大致的qps, 最简单的做法就是多线程疯狂的call计算平均时间,这里给出一段测试代码:
    class PressTest(object):
        def __init__(self):
            pass
    
        def get_html(self, url, headers=conf_test.HEADERS, data=None):
            if data:
                data = json.dumps(data)
            req = urllib2.Request(url=url, headers=headers, data=data)
            response = urllib2.urlopen(req)
            html = response.read()
            return html
    
        def get_test(self, api_url):
            result = self.get_html(url=api_url)
            if not result:
                print "url %s result is none" %api_url
                return
            return
    
        def post_test(self, api_url, **kwargs):
            import time
            start_time = time.time()
            result = self.get_html(url=api_url, data=kwargs)
            print result
            if not result:
                print "url %s result is none" % api_url
            end_time = time.time()
            all = end_time - start_time
            print all
    
    
    if __name__ == '__main__':
    
        press_test = PressTest()
        print "requesting........."
        api_url = 'https://xxx接口1'
        api_url2 = 'https://xxx接口2'
        start = time.time()
        times = 400
        for i in range(times):
            t1 = threading.Thread(target=press_test.get_test, args=(api_url,))
            t2 = threading.Thread(target=press_test.get_test, args=(api_url2,))
            t1.start()
            t2.start()
            t1.join()
            t2.join()
        end = time.time()
        ave = (end - start) / 800.0
        print "count:%d, start_time :%s, now_time: %s, average_qps: %s" % (800, str(start), str(end), str(ave))
    • 这里是开了400个线程并发call这两个常用接口,最后计算出qps(每秒的请求数),如果能达到100次/秒,基本上几千人同时在线没啥问题,哈哈

    总结

    • emmmm……,整个开发流程差不多就这样,比较常用几个点就这些,还有很多东西没有介绍比如短信验证,数据库性能方面的问题,下回再和大家交流,有啥问题请留言,有时间都会回复,总的来说微信小程序开发还是挺有意思的, 觉得有帮助的朋友麻烦点个赞!

    相关资料

    [1] Flask入门
    [2] Mac安装Nginx
    [3] vim常用技巧
    [4] nginx + gunicorn + supervisor部署技巧
    [5] 阿里云ssl证书配置
    [6] http和https的区别
    [7] 微信支付文档
    [8] 微信商户证书
    [9]七牛云python sdk
    [10]图片http转https
    [11]小程序消息模板发送技巧
    [12]Django QuerySet orm框架学习

    展开全文
  • 怎么快速学习App后台开发

    万次阅读 2016-06-04 21:11:43
    本人从去年7月份开始持续到今年2月份,终于写完了书籍《App后台开发运维和架构实践》,这是一本教导刚入行的同学快速学习App后台开发的书籍。
  • 后台开发 vs App应用开发?

    千次阅读 2018-08-13 09:02:24
    原文链接地址:后台开发 vs App应用开发? 最近很多老铁从app转做后台了,说app招聘的太少了,基本混合开发一出,app原生开发需求越来越少。本身一个公司安卓可能2人以上,ios可能始终就是一个人。 App...
  • 其实对于后台开发来说原理都差不多。只不过app的后台开发和web不一样的地方在于传输数据格式不一样,一般来说web访问后返回的是一个html页面,少部分是json格式;而一般app的后台开发大部分直接传json格式数据(也有...
  • C++后台开发学习路线

    千次阅读 多人点赞 2019-02-13 11:42:35
    后台开发包括的知识点很多,包括语言基础,算法,linux编程基础,linux内核,网络,数据库,分布式等等。面面俱到很难,一个领域钻研的很深也很难。我认识的大神里有把C++语言吃的非常透的,也有实验室就是搞分布式...
  • 小程序后台开发的那些事

    千人学习 2017-08-15 14:55:28
    小程序“简约而不简单”,虽提供的功能及界面简约,但对后端却有着更...本课程带你了解微信小程序后台开发关键技术点,并通过真实案例,教大家掌握小程序开发中的关键环节,是开发者入门微信小程序开发的必备视频教程。
  • kotlin后台开发 应用

    2019-01-26 21:19:34
    kotlin后台 开发应用 koltin 作为更加灵活语言逐渐侵入开发各个领域
  • Django微信小程序后台开发教程

    万次阅读 多人点赞 2018-10-19 20:38:05
    Django微信小程序后台开发教程1 申请小程序,创建hello world小程序2 添加交互框和按钮3 在服务器配置hello django4 实现计算器接口5 配置服务器将后端与微信小程序连接5.1 uwsgi配置5.2 http协议(80端口)下的...
  • C++后台开发

    千次阅读 2018-11-25 12:33:15
    C++后台开发之我见  --------2017.2.6  工作也快两年了,偶然看到自己以前写过的一些技术博客,发现自己自毕业后一直没有更新过自己的技术博...
  • 基本上一样的,ssh也可以为手机APP开发后台。其实对于后台开发来说原理都差不多。只不过app的后台开发和web不一样的地方在于传输数据格式不一样,一般来说web访问后...而一般app的后台开发大部分直接传json格式数据
  • Linux后台开发工程师专栏 一、算法与设计专题 二、后台组件编程专题 三、代码化过程专题 视频文档资料获取+1035101242(VX同号)。 系统学习视频链接:...
  • 微信公众号后台开发总结

    万次阅读 2018-03-19 17:24:10
    微信公众号后台开发总结一、项目简介当前需要做一个公众号后台,前期需要实现的功能有:(1) 在用户关注公众号时便获取用户的信息同时还要将用户信息存入数据库。(2) 在用户给公众号发送消息时,后台能够对消息...
  • 腾讯IEG后台开发(已拿到offer)

    万次阅读 多人点赞 2019-03-11 22:04:40
    当时投递岗位的时候没有看清要求,写着后台开发岗,招C/C++/Java,果然越靠前越重要。。本来想投的是Java岗,奈何鹅肠后台C++偏多。结果面试的时候面的全是C++和Linux,Java一点没问。全程大概25分钟,总结如下。 ...
  • 求Android后台开发流程

    2016-07-29 07:27:18
    最近想转行做Android后台开发,但不大清楚后台开发的流程,中间需要做什么准备,求详细介绍!!
  • 后台开发的语言比较

    千次阅读 2018-05-10 18:18:26
    最近因为个人兴趣和项目团队安排,我开始在学习后台开发,我们项目后台使用python写的,运用tonardo框架。因为对后台开发不是很理解,对各种语言也不懂,我上网查了各互联网公司的后台语言,并顺便比较比较。目前...
  • Java Web 后台开发效率提高

    千次阅读 2018-07-13 04:55:13
    当前 Java 开发后台项目较为主流,针对 Web 后台开发效率的提高,是每个项目管理者需要面临的问题。本场 Chat 对于系统应用开发效率提高将根据作者多年开发总结的经验进行下交流,方便管理者节约开发成本。 读者交流...
  • 游戏后台开发工程师

    千次阅读 2017-11-16 09:46:17
    2、负责手游版本的后台开发和性能优化; 3、负责后台运营系统的设计优化。 任职要求: 1、计算机相关专业本科及以上学历,能熟练阅读英文技术文档 2、1年以上Unix/Linux下Server开发经验; 3、
  • 其实对于后台开发来说原理都差不多。只不过app的后台开发和web不一样的地方在于传输数据格式不一样,一般来说web访问后返回的是一个html页面,少部分是json格式;而一般app的后台开发大部分直接传json格式数据(也有...
  • C++后台开发学习路线(已签腾讯后台开发

    万次阅读 多人点赞 2019-03-18 21:32:11
    技术交流可以加: 本人微信:xcg852390212 本人qq:852390212 学习交流qq群1(已满): 962535112 学习交流qq群2: 780902027 ...找完工作后一直想找时间写点东西,由于在忙各种事情,一直拖到现在。...
  • 钉钉自定义机器人-后台开发

    万次阅读 2018-08-04 22:49:18
    钉钉自定义机器人-后台开发,我们通过配置就好了,方便操作!下面实例是22点22分发送不同的消息。 官方文档:https://open-doc.dingtalk.com/docs/doc.htm?treeId=257&amp;amp;amp;articleId=106438&amp;...
  • 后台开发面试问题整理

    万次阅读 多人点赞 2016-02-27 22:07:53
    实习、校招中后台开发的面试问题
  • 小程序后台开发sdk

    千次阅读 2018-07-13 12:39:41
    小程序后台开发sdk链接:https://github.com/tencentyun/wafer2-node-sdk
  • 后台开发方向学习路线

    千次阅读 2019-05-19 14:17:18
    自从找完工作之后,好久没有观看牛客了,今天发现一个师弟关于[后台开发方向的总结](https://www.nowcoder.com/discuss/188367?type=0&order=4&pos=11&page=2),个人觉得总结的很到位,再次分享给后来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 77,926
精华内容 31,170
关键字:

后台开发