加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 资源 > 正文

小程序稻草人图床神器,前后端开源

发布时间:2020-12-14 19:15:23 所属栏目:资源 来源:网络整理
导读:源码地址: 小程序源码 http s: //github. com /w77996/mini-straw 后台源码 http com /w77996/ hi -straw 复制代码 体验一下 之前乘着换工作的间隙撸的,一方面练习一下小程序,学过之后没怎么应用,一方面写点笔记啥的,项目断断续续做了两个月,只是一个

源码地址:

小程序源码 https://github.com/w77996/mini-straw  
后台源码 httpcom/w77996/hi-straw  
复制代码

体验一下

之前乘着换工作的间隙撸的,一方面练习一下小程序,学过之后没怎么应用,一方面写点笔记啥的,项目断断续续做了两个月,只是一个简单的图片上传工具,觉得不错的话记得给个star

小程序

  1. 小程序授权,登录
  2. 父组件与子组件相互通信
  3. 小程序分享,意见与建议,客服功能,文件上传
  4. flex布局的使用
  5. Promise的使用,业务model封装
  6. 插槽的使用,动画效果

项目目录结构

mini-straw
    ├── component -- 组件
    |    ├── file -- 文件组件
    |    ├── image-button -- 图片按钮组件
    |    ├── search -- 查找页面组件
    |    ├── tag -- 标签组件
    ├── images -- 图片目录
    |    ├── icon -- icon图片
    |    ├── tab -- tab图片
    ├── model -- 封装的model
    ├── pages -- 页面
    |    ├── about -- 关于页
    |    ├── auth -- 授权页
    |    ├── file -- 文件页
    |    ├── index -- 首页
    |    ├── launch -- 启动页面
    |    ├── my -- 个人中心
    └── utils -- 工具
复制代码

后台:

技术栈:spring boot + druid + mybatis + jwt

  1. 微信登录,jwt授权
  2. 注解及AOP的使用
  3. maven多环境打包,docker使用
  4. shell脚本自动化部署
  5. nginx反向代理及https配置
  6. 七牛云文件操作

hi-straw ├── common -- 公共模块 ├── config -- 配置模块 ├── controller -- controller接口 ├── core -- 核心业务模块 | ├── annontaion -- 注解 | ├── aop -- aop实现 | ├── constant -- 常量 | ├── filter -- 拦截器 | ├── jwt -- jwt相关 | └── result -- 结果返回 ├── entity -- 实体类 | ├── dto -- 数据传输 | └── vo -- 页面传输 ├── exception -- 全局异常 ├── mapper -- dao层 ├── service -- service层 └── util -- 工具类 复制代码

小程序详解

[TOC]

mini-straw

项目结构

开屏页

1.判断网络状态

使用?wx.getNetworkType({})?可获取当前网络状态,?networkType?值?wifi/2g/3g/4g/unknown(Android下不常见的网络类型)/none(无网络)

//判断网络状态
wx.getNetworkType({
    success: res => {
    if (res.networkType == "none") {
        wx.showToast({
            title: '嗷~~网络不可用',icon: 'none',duration: 2000
        })
        return;
    }
    },})
复制代码

2.判断授权状态

wx.getSetting({})?获取授权状态,在获得?data?后取?data.authSetting['scope.userInfo']?判断授权状态

]) {
        //已授权,执行登陆
        wx.getUserInfo({
            success: data => {
                    console.log("userInfo {}",data)
                    let userInfo = data.userInfo;
                    wx.setStorageSync('userInfo',userInfo);
                    //执行登陆操作
                    this._userLoginGetCode(userInfo);
            }
        });
        wx.setStorageSync('authorized',true);
    } else {
        "未授权")
        //跳转至授权页
        let timer = setTimeout(() => {
                wx.redirectTo({
                        url: '/pages/auth/auth'
                })
        },2000)

    }
    }
});
复制代码

若授权,则调用?wx.getUserInfo({})?获取微信用户信息,信息获取完成后调用?wx.login({})获取小程序的?code?,通过?code?向后台获取用户openId及token。

,}),0);">2000)
            });
        } else {
                '登录失败!' + res.errMsg)
        }
        }
    })
},复制代码

3.跳转页面

  • 跳转?/pages/auth/auth?页面使用的是?wx.redirectTo({})
  • 跳转?/pages/index/index?页面使用的是?wx.switchTab({})?
    因为?/pages/index/index?是小程序tab页,使用?wx.redirectTo({})?无法跳转

授权页

授权需制定button按钮,加入?open-type='getUserInfo'?属性,?bindgetuserinfo?调用自定义方法?onGetUserInfo?。

<button class="auth-button" open-type='getUserInfo' bindgetuserinfo="onGetUserInfo">好的</button>
复制代码

onGetUserInfo?接受授权状态及授权获取的用户信息,再进行?code?获取,通过?onGetUserInfo: function(e) { console.log(e) const userInfo = e.detail.userInfo; if (userInfo) { //通过`code`向后台获取用户openId及token。 this._userLoginGetCode(userInfo); } },复制代码

主页

1. 图片按钮插槽组件

在?component?目录下的?images-button?组件,做了简单的图片插槽统一,在分享按钮,用户登录按钮,文件上传按钮均可以使用。?plain="{{true}}"?代表button背景透明

<button  open-type="{{openType}}" plain={{true}}" class="container">
  <slot name="img"></slot>
</button>
复制代码

options?需要开启插槽功能,添加?multipleSlots: true?
open-type="{{openType}}"?父组件将参数传入子组件,子组件在?properties?属性中可以获取到父组件传来的openType数据,通过?this.properties.openType?可以获取属性值

options: {
    // 开启插槽
    multipleSlots: true
  },/**
   * 组件的属性列表
   */
  properties: {
    openType: {
      type: String
    }
  },复制代码

index?页面引入组件,需要在?index.json?中添加组件路径

{
  "usingComponents": {
    "btn-cmp": "/component/image-button/index"
  }
}
复制代码

2. 上传文件

主要使用到?wx.chooseImage({})?进行图片的选择,选择后使用?wx.uploadFile({})?上传图片至服务器

,'compressed'],136);">// 可以指定是原图还是压缩图,默认二者都有
  sourceType: ['album',0);">'camera'],136);">// 可以指定来源是相册还是相机,默认二者都有
  success: function(res) {
    // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
    let tempFilePaths = res.tempFilePaths;
    console.log(tempFilePaths)
    wx.uploadFile({
      header: {
        "Authorization": "Bearer " + wx.getStorageSync("token")
      },url: config.apiBaseUrl + '/file/upload',filePath: tempFilePaths[0],name: 'file',success: (res) => {
        wx.showToast({
          title: "上传成功~",0);">2000
        })
      },fail: (res) => {
        wx.showToast({
          title: res.data.msg,0);">2000
        })
      }
    })

  }
})
}
复制代码

列表页

1.search组件的显示和隐藏

固定列表页搜索header位置,点击header显示?search?组件,在?search?组件点击取消则隐藏?search?组件,此处设计子组件向父组件传递消息

  • 引入search组件
"usingComponents": {
    ...
    "search-cmp": "/component/search/index"
  }
复制代码
  • 使用searchPage参数判断?search?组件的,默认为false,在点击header时更新searchPage为true,显示?search?组件
  • search?页面点击取消,向父组件发送一个?this.triggerEvent('cancel',{},{});?事件,在xml中的?search-cmp?添加?cancel?事件的通知绑定
  • #file页面中的search-cmp组件
    <search-cmp  wx:if="{{searchPage}}" bind:cancel="onCancel"></search-cmp>
    复制代码

    父组件?file?页面绑定子组件传来的?cancel?事件通知,就调用?onCancel?方法,在?onCancel方法中获取事件响应,将?searchPage?参数修改为false,?search?组件就隐藏起来了

    ,{});
     
    },254);'>2.文件列表
    

    1.获取列表信息传递给file组件

    page?中的file页面,获取到后台传来的fileList数据,引入file组件,?file="{{item}}"?将数据传入子组件

    component?中的file组件,在?properties?添加属性?file?来接收父组件传来的数据

    file组件在xml页面中使用?{{file.fileName}}?即可获取到对象信息,相应的数据也会呈现在页面上

    3.粘贴板操作

    <image src="images/copy.png" bindtap="onCopy"></image>
    复制代码

    图片点击响应方法?onCopy?,?onCopy?调用?wx.setClipboardData({})?可以将数据复制到粘贴板

    onCopy: function (event) {
          console.info(event)
          this;
          wx.setClipboardData({
            data: _this.properties.file.filePath,success: function(res) {
              wx.showToast({
                title: '图片地址复制成功',})
            }
          });
    
    复制代码

    4.删除操作

    子组件将数据传递给父组件,点击删除图片出发?onDelete?方法,249); border: 0px; font-weight: 600; font-size: 14px;'>this.triggerEvent('del',{fileId},{});?将文件ID发送到父组件

    onDelete: let fileId = this.properties.file.id;
          this.triggerEvent('del',{});
        },254);'>父组件file页面绑定子组件传来的?del?事件

    调用?onDelete?出发网络请求去完成删除文件的逻辑,删除成功后重新刷新文件列表

    ,})
            this.setData({
                    pageNum: fileList: []
            });
            this._getFileList();
        })
    },254);'>我的页面
    

    1.意见和建议

    小程序自带用户反馈功能,使用?button?跳转至网页,用户可以填写相关反馈,?open-type?设置为?feedback

    2.小程序客服
    

    小程序的?button?中的?open-type?拥有开放能力,在微信公众平台中启用客服功能,添加客服人员,在代码中添加?button?即可弹出客服聊天界面,249); border: 0px; font-weight: 600; font-size: 14px;'>contact

    3.小程序分享
    

    此处使用插槽,249); border: 0px; font-weight: 600; font-size: 14px;'>share

    <btn-cmp open-"share">
        <image slot="img" src="images/share.png" />
    </btn-cmp>
    复制代码

    动画

    小程序动画官方文档

    开屏动画,设置文字透明度,从0到1,渐渐显示,主要使用到?opacity?去设置组件的透明度,先创建一个动画?animationTip?,持续800ms,然后在?setTimeout(function () {})?中设置动画出现时间

    var animationTip = wx.createAnimation({
          //持续时间800ms
          duration: 800,timingFunction: 'ease',});
        this.animationTip = animationTip;
        animationTip.opacity(0).step()
        this.setData({
          animationTip: animationTip.export()
        })
        setTimeout(function () {
          animationTip.opacity(1).step()
          this.setData({
            animationTip: animationTip.export()
          })
        }.bind(this),0);">500)
    复制代码

    部署

    1. 修改?utils?目录下的?config.apiBaseUrl?,改成自己的域名,上传到微信公众号平台,在版本管理中进行发布
    后台功能详解
    

    hi-straw

    数据库设计

    ,0);">`file_path` varchar(255) '文件路径',0);">`file_name` 100) '文件名',0);">`file_size` 10) '文件大小',0);">`props` NULL,0);">`status` tinyint(5) DEFAULT '0' '0.正常 -1.删除',0);">`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT'创建时间',PRIMARY KEY (`id`),KEY `user_id` (`user_id`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=27 CHARSET=utf8mb4 '用户文件列表';
    复制代码
    ,0);">`nickname` '用户昵称',0);">`user_logo` 250) '用户logo',0);">`phone_num` '手机号',0);">`open_id` 55) '微信openId',0);">`union_id` '微信union_id',0);">`password` 50) '密码',0);">`uuid` '自定义生成的uuid',0);">`last_login` datetime '最后登陆时间',51); font-weight: 700;">UNIQUE `open_id` (`open_id`) USING HASH
    ) 12 '用户表';
    复制代码
    ,0);">`left_size` '5242880' '剩余文件大小',0);">`total_size` 11)'用户文件空间大小',0);">`file_num` '文件数量',0);">`is_vip` tinyint('是否为vip,1.是 0.否',0);">43 '用户文件信息';
    复制代码
    ,0);">`location` '位置',0);">`platform` '平台',0);">`birthday` datetime '生日',0);">`user_id`)
    ) InnoDB '用户详细表';
    复制代码

    代码详解

    前期准备

    • linux服务器及MySql数据库
    • 七牛云账号,可以去七牛云官网申请账号
    • HTTPS证书阿里云获取免费证书
    • 微信公众平台小程序开发者账号

    七牛云文件上传

    代码?com.w77996.straw.util.QiNiuUtil

    1.七牛云账号申请

    七牛云官网申请账号,获得?AccessKey?,249); border: 0px; font-weight: 600; font-size: 14px;'>SecretKey?,并设置七牛云图片?bucket

    2.七牛云SDK引入
    

    pom.xml?文件引入七牛云仓库

    2. 七牛云token生成
    
    /**
         * 七牛云生成token
         *
         * @param fileName
         * @return
         */
        public QiNiuAuth generateToken(String userId,String fileName) {
            Auth auth = Auth.create(accessKey,secretKey);
            String key = "upload/file/000/" + userId + "/" + fileName;
            StringMap putPolicy = new StringMap();
            putPolicy.put("returnBody",0);">"{"key":"$(key)","hash":"$(etag)bucket":"$(bucket)fsize":$(fsize)}");
            long expireSeconds = 3600;
            String upToken = auth.uploadToken(bucket,key,expireSeconds,putPolicy);
            Map<String,0);">String> resultMap = Maps.newHashMapWithExpectedSize(3);
            resultMap.put("domain",0);">"https://www.w77996.cn");
            resultMap.put("key",key);
            resultMap.put("upToken",upToken);
            return new QiNiuAuth("https://www.w77996.cn",upToken);
        }
    复制代码

    3.上传文件代码编写

    4.删除图片
    
    注解+AOP接口限流
    

    1. 注解编写

    com.w77996.straw.core.annotation.Limiter

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Limiter {
    
        /**
         *
         * @return
         */
        String value() default "";
    
        /**
         * 每秒向桶中放入令牌的数量   默认最大即不做限流
         * @return
         */
        double perSecond() default Double.MAX_VALUE;
    
        /**
         * 获取令牌的等待时间  默认0
         * int timeOut() default 0;
    
        /**
         * 超时时间单位
         * @return
         */
        TimeUnit timeOutUnit() default TimeUnit.MILLISECONDS;
    }
    
    复制代码

    2.AOP实现

    com.w77996.straw.core.aop.RateLimitAspect

    3. 注解使用
    

    限定每秒只能调用一次,如果超出,则返回?Result.error(ResultCode.BUSY)

    JWT实现
    

    1.jwt生成

    使用JwtUtil生成jwt Token

    2.token解析成userId
    

    将userId放入token中,在请求接口时可以通过请求Header获取Bearer {token}进行解码,从而获取userId。

    3.拦截器+注解方式进行token鉴权
    

    com.w77996.straw.core.annotation.IgnoreToken?
    先设置忽略token的注解

    com.w77996.straw.core.filter.TokenFilter?
    拦截器?TokenFilter?实现?HandlerInterceptor?,在每次请求进来时进行拦截,在调用controller之前都会调用?perHandle?,所以在?perHandler?内获取方法名的注解,判断是否有ignoreToken的注解,然后进行jwt的校验。

    @Override
        public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            IgnoreToken ignoreToken = handlerMethod.getBeanType().getAnnotation(IgnoreToken.class);
            log.info("enter preHandle {}",0);">request.getRequestURL());
            if (ignoreToken == null) {
                ignoreToken = handlerMethod.getMethodAnnotation(IgnoreToken.class);
            }
            if (ignoreToken != null) {
                "ignoreToken not null");
                return true;
            }
            "ignoreToken  null");
            String token = request.getHeader(if(token != null){
                "token is {}",token);
                "admin".equals(token.substring(7))) {
                    return true;
                }
                Claims claims = JwtHelper.parseJWT(token.substring(7),Audience.BASE64SECRET);
                if(claims != null){
                    "claims is {} {}",claims.toString(),claims.getSubject());
                    return true;
                }else{
                    "claims is null");
                    throw new GlobalException(ResultCode.ERROR_AUTH);
                }
            }
            return false;
        }
    
    复制代码

    4.实现web拦截器

    com.w77996.straw.config.WebMvcAdapterConfig?不拦截?/druid/*?的接口

    Druid监控配置
    

    com.w77996.straw.config.DruidConfig?
    项目运行后访问?http://ip:port/druid?,输入账号?admin?密码?amdin?即可访问

    全局异常拦截
    

    全局异常拦截主要是依靠?@RestControllerAdvice?注解,在方法上使用?@ExceptionHandler(value = Exception.class)?代表拦截所有Exception,然后进行对应的操作

    微信登录
    

    需要在微信公共平台获取对应的appId,appSec,小程序获取到code之后发送给后台,后台获取code向微信发送http请求,使用的是restTemplate,但是需要注意编码,微信编码返回是ISO-8859-1;调用成功后可以拿到用户的openId,再去数据库中获取对应的用户信息,进行登陆更新及用户创建的逻辑处理

    spring boot + maven多环境打包
    

    1.resouce下的yml文件

    项目环境分为?dev?和?prod?两种,?resource?文件下默认加载?application.yml?。

    application.yml
    
    @spring.profiles.active@?对应的为pom.xml文件中profiles下的?spring.profiles.active?属性

    2.pom.xml配置

    默认情况下使用?dev?环境下的配置信息

    3.不同环境打包
    
    • 打包?prod?环境:执行?mvn package -Pprod -DskipTests
    • 打包?dev?环境:执行?mvn package -Pdev -DskipTests

    4.项目打包命名

    properties?属性中添加时间格式,然后再?build?中添加?fileName?格式化文件名。

    打包完成后生成的jar:?hi-straw-1.0.0-prod_2019-04-091533.jar

    shell脚本编写

    登陆服务器,clone项目至?/root/repo_git/?目录下,执行进入?script?目录下,执行?./build.sh?,需要将?RELEASE_HOST?换成你自己的服务器地址,方便做保存备份

    执行?docker images

    查看刚刚打包好的docker镜像

    maven + docker 打包部署

    1.docker环境安装

    卸载老旧的版本(若未安装过可省略此步):

    sudo apt-get remove docker docker-engine docker.io
    复制代码

    安装最新的docker:

    curl -fsSL get.docker.com -o get-docker.sh
    sudo sh sh
    复制代码

    确认Docker成功安装:

    docker run hello-world
    复制代码

    2.项目编译打包

    src/main/docker?下建立?dockerFile?文件

    pom.xml配置docker打包,配合shell脚本在linux实现maven自动打包docker

    <!-- Docker maven plugin -->
        <plugin>
            <groupId>com.spotify</artifactId>docker-maven-plugin</version>
            <configuration>
                <imageName>${project.artifactId}</imageName>
                <dockerDirectory>src/main/docker</dockerDirectory>
                <resources>
                    <resource>
                        <targetPath>/</targetPath>
                        <directory>${project.build.directory}</directory>
                        <include>${project.build.finalName}.jar</include>
                    </resource>
                </resources>
            </configuration>
        </plugin>
    <!-- Docker maven plugin -->
    复制代码

    执行?docker images?查看刚刚打包的docker镜像

    docker run --name hi-straw -p 8989:8989 -t hi-straw?启动镜像

    dockers ps?查看已启动docker镜像

    nginx配置https

    1.安装nginx

    登陆到服务器,执行

    $ apt-get update // 更新软件
    $ apt-get install nginx // 安装nginx
    复制代码

    2. 获取证书

    可以去阿里云获取免费证书

    将生成的证书放入?/etc/nginx/sites-enabled/cert/?(具体看你将nginx安装在哪个目录下)

    3. 配置nginx文件

    新建一个https.conf

    配置完成后,检查一下nginx配置文件是否可用

    配置正确后,重新加载配置文件使配置生效

    如需重启nginx,用以下命令:

    部署
    

    修改?resource?下的?application-dev.yml?和?application-prod.yml?中你自己申请的微信息及七牛云信息修改,修改数据库地址,用户名和密码

    spring:
      datasource:
        name: graduate
        driver-class-name: com.mysql.jdbc.Driver
        url: 数据库地址
        username: 数据库用户名
        password: 数据库密码
    复制代码

    script?目录下?build.sh

    RELEASE_HOST="你自己的服务器地址"
    复制代码

    项目的服务器7月15号到期了……哪位大佬资助一下服务器,感激不尽

    捐助

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读