-- 创造无限可能
小程序网站定制开发
专注APP开发,小程序开发,软件开发,OA办公系统,CRM管理系统,ERP系统,供应链管理,物联网开发,覆盖政府,金融,电商,汽车,教育,医疗,零售,能源,制造,电信,交通等众多领域,立足广西

在使用php对接对外接口时,需要使用到curl,但是在这个过程中遇到了一个问题:当前curl版本是7.29,建议升级至7.40或更高版本。

错误提示是curl版本低于7.40导致失败

先到服务器查看当前的curl版本:

显示的是7.29

解决办法:升级curl版本

yum install wget gcc openssl-devel -y
wget https://curl.haxx.se/download/curl-7.67.0.tar.gz
gunzip -c curl-7.67.0.tar.gz | tar xvf -
cd curl-7.67.0
./configure --with-ssl --prefix=/usr/local/curl
make
make install
echo "export PATH=/usr/local/curl/bin:$PATH" >> /etc/profile
source /etc/profile
curl --version

原文链接:https://blog.csdn.net/shida_csdn/article/details/117786933

本文是使用htinkphp6 + 阿里大于发送短信的使用案例

在接口中使用到了”alibabacloud/sdk”: “^1.8” 的sdk,需要在此之前事先通过composer安装



/**
     * 发送短信
     * @param string $mobile 手机号码
     * @param array $templateParam 设置短信模板参数
     * @param string $templateCode 模板code
     * @return bool 是否发送成功
     */
    public function sendVerifySms($mobile, $templateParam, $templateCode)
    {
        try {
            //获取配置信息
            $config = [
                    'access_key_id' => 'xxx',
                    'access_key_secret' => 'xxxx',
                    'sign_name' => 'xx平台',
                    'template_code' => [
                        'verify' => 'xxx',
                    ]
                ];

            // 创建客户端
            AlibabaCloud::accessKeyClient($config['access_key_id'], $config['access_key_secret'])
                ->regionId('cn-hangzhou')
                ->asDefaultClient();


            //调用阿里云短信发送接口
            $result = AlibabaCloud::rpc()
                ->product('Dysmsapi')
                //可根据实际情况选择不同的服务地区
                ->regionId('cn-hangzhou')
                ->version('2017-05-25')
                ->action('SendSms')
                ->method('POST')
                ->host('dysmsapi.aliyuncs.com')
                ->options([
                    'query' => [
                        'RegionId' => 'cn-hangzhou',
                        'PhoneNumbers' => $mobile,
                        'SignName' => $config['sign_name'],
                        'TemplateCode' => $templateCode,
                        'TemplateParam' => json_encode($templateParam),
                    ],
                ])
                ->request();

            //判断短信发送状态
            if ($result->toArray()['Code'] == 'OK') {
                return true;
            } else {
                return false;
            }
        } catch (ClientException|ServerException $e) {
            return false;
        }
    }

功能示例图如下

用户点击一键登录,用户点击允许后获取用户手机号码

前端代码:

<button class="confirm-btn" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber" style="background: linear-gradient(55deg, #377ffd, #5db7fb);">
      一键登录
</button>

js代码

    // 手机号授权
    onGetPhoneNumber(e){

        // 用户已授权
        if (e.detail.errMsg === 'getPhoneNumber:ok') {
            const iv = e.detail.iv
            const code = e.detail.code
            const encryptedData = e.detail.encryptedData
            // 将 encryptedData 和 iv 发送到后端解密
            this.quickLogin(encryptedData, iv)
        } else {
            // 用户拒绝授权
            uni.showToast({
                title: '授权失败',
                icon: 'error'
            })
        }
    },


    quickLogin(_encryptedData=null, _iv=null){
        const that = this
        uni.login({
            provider: 'weixin',
            success: function(loginRes) {
                uni.getUserInfo({
                    success: (userInfoRes) => {

                        const iv = _iv ?? userInfoRes.iv 
                        const encryptedData = _encryptedData ?? userInfoRes.encryptedData

                        http.post('/user/login', {
                            iv: iv,
                            register: true,
                            code: loginRes.code,
                            encryptedData: encryptedData,
                        }).then(res => {
                            if(res.code == 0){
                                //登录成功,设置用户信息


                            }else{
                                uni.showModal({
                                    title: '登录失败',
                                    content: res.msg,
                                    showCancel: false,
                                    confirmText: '确定',
                                })
                            }
                        })

                    },fail: (res) =>{
                        console.log('失败', res)
                    }
                })
            },fail: (res) =>{
                console.log('失败', res)
            }
        })
    }

后端使用的是thinkphp6,和easyWeChat的SKD4.0版本
文档:https://easywechat.com/4.x/

    /**
     * 一键登录
     */
    public function quickLogin()
    {
        $param = $this->request->param();

        $code = $param['code'];
        $iv = $param['iv'];
        $encryptedData = $param['encryptedData'];

        $app = Factory::miniProgram($config);

         //根据code获取session_key
         $wxUserInfo = $this->app->auth->session($code);

        //消息解密。比如获取电话等功能,信息是加密的,需要解密。
        $data = $this->app->encryptor->decryptData($wxUserInfo['session_key'], $iv, $encryptedData);

        //输出
        dump($data);

//        [
//            "phoneNumber" => "手机号"
//            "purePhoneNumber" => "手机号"
//            "countryCode" => "86"
//            "watermark" => array:2 [
//            "timestamp" => 1721456497
//                "appid" => ""
//            ]
//        ]

        //登录逻辑...

    }

在vue中,我们可能需要再created中获取到dom元素进行操作,但是呢在created中获取dom元素会获取不到,应为dom还没有渲染完,找不到dom元素导致获取不到,所以可以在 this.$nextTick()延迟加载中去获取dom元素

<div ref="audioPlayer">
    我是元素
</div>


created() {
    //在这里获取不到div元素,应为dom还没有渲染加载完,找不到div
     //const audioPlayer = this.$refs.audioPlayer;

    //延迟执行
    this.$nextTick(() => {
        //在这里才能获取到,这时dom渲染加载完了
         const audioPlayer = this.$refs.audioPlayer;
    });

},

  created() {

    this.$nextTick(() => {
      console.log(4663)
      this.playAudio()
    });

  },

场景:因为微信小程序的文件包大小限制,只能上传2M及以下的文件包,超过2M时就无法上传

解决方法:需要进行分包
微信文档分包教程文档:
https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/basic.html
https://developers.weixin.qq.com/community/develop/doc/00040e5a0846706e893dcc24256009

当前使用的是uniapp,一下教程是uniapp的分包教程
uniapp分包文档
https://uniapp.dcloud.net.cn/collocation/manifest.html#%E5%85%B3%E4%BA%8E%E5%88%86%E5%8C%85%E4%BC%98%E5%8C%96%E7%9A%84%E8%AF%B4%E6%98%8E

1、在对应平台的配置下添加”optimization”:{“subPackages”:true}开启分包优化

2、pages.json里进行分包
pages是默认文件路径,subPackages是需要分包的文件路径

3、分包之后在行进打包

分包成功,这里可以看到主包已经小于2M,即可上传成功

问题

centos7 安装好php后,执行php报错

php: error while loading shared libraries: libonig.so.2: cannot open shared object file: No such file or directory

原因分析

1.该库不存在
2.库存在但是没有正确引用

解决过程

1.查询库确认库是否真实存在:find / -name '*libonig*'
2.库存在则把文件复制到/usr/lib64下,或者正确配置库文件
3.库文件不存在则yum install libonig

当前使用的php框架是fastadmin,nginx版本是1.20
问题描述:
在宝塔面板添加站点并设置thinkphp伪静态后,网站前台能正常打开(例如:www.xxx.com/index.php/article/info),但是后台无法打开(www.xxx.com/admin.php/index/login)

但是以为一直是伪静态问题,不支持pathinfo导致的,查询很多资料后发现是nginx的php.conf配置问题

(示例:比如我的nginx下目录目录BtSoft\nginx\conf\php)
找到nginx下的conf下的对应php.conf配置,将try_files $uri =404;注释掉(我用的php版本是php73)

保存后重启nginx即可

1、pages.json页面找到页面配置,添加 enablePullDownRefresh

{
            "path": "pages/order/list-mine",
            "style": {
                "navigationBarTitleText": "订单列表",
                "enablePullDownRefresh": true ,//开始下拉刷新
                "backgroundTextStyle": "dark" // 下拉 loading 的样式,仅支持 dark/light
            }
        },

2、在 js 中定义 onPullDownRefresh 处理函数(和onLoad等生命周期函数同级),监听该页面用户下拉刷新事件。

//下拉刷新
  onPullDownRefresh(){
  //下拉请求接口
    this.getOrder();

  },

3、在接口执行成功后关闭下拉动画

    getOrder() {
      let query = {}
      query = {
        keyword: this.keyword
      }

      http.get("/order/query", query).then(res => {
        if (res.code == 0) {
          this.order = res.data.rows
        }

        //停止下拉刷新显示
        uni.stopPullDownRefresh();
      })
    },

场景:

在前端业务的开发中,我们可能会封装很多公共组件。大部分时候因为忙于业务开发,并不会为这些公共组件进行文档编写、测试。在进行复用的时候,需要在项目中查看源码去查看该组件的作用、参数和事件。这种组件开发的方式在前端项目规模不大的时候还能接受,但当项目到达一定规模后,一般会存在以下问题:

  • 重复造轮子:因为没有统一的组件展示,其他开发者会不清楚组件已经在项目中实现,出现重复造轮子的现象。
  • 组件通用性不强:组件和项目逻辑强耦合,导致重复利用率不高。
  • 不知道如何使用:没有组件文档的存在,其他开发者需要去查看源码弄明白组件有哪些 event 和 props。增加了组件的使用难度

    storybook/vue

处理

执行npm cache clean --force

npm config set registry https://registry.npmmirror.com

1、第一种
传递参数

let data = [
    title: '标题',
    state: 1
]
uni.$emit('responseData', data); // 发送全局事件,传递数据

获取参数

  onShow() {
        const that = this;
        uni.$on('responseData', function(data) { // 监听全局事件,并获取数据

             // 使用 data 进行后续操作
            that.responseData = data.data

            if(that.signature_type == 1){
                that.data.signature = that.responseData.url
            }else{
                that.data.parent_signature = that.responseData.url
            }
        });
  }

2、第二种,设置缓存的方式

uni.setSystemInfoSync("responseData", data)

获取参数

uni.getSystemInfoSync("responseData")

3、第三种,url传递(如果是多个参数的话,或者参数不固定需要一个个拼接,有弊端)

uni.navigateTo({
    url: '/pages/userCourse/detail?state=1&id=10'
})

获取参数

  onLoad(param) {
        this.id=param.id
        this.state=param.state
  },
<u-upload 
        :file-list="picList" 
        :action="url" 
        :before-upload="beforeUpload" 
        :before-remove="beforeRemove" 
    ></u-upload>

js:

    beforeUpload(index, list) {
      this.picList = []
      // console.log('list',list);

      let i = 0;
      list.map(async item => {
        this.picList.push({
          url: item.url
        })

        if(i == index){
            let result = await this.uploadFilePromise(item.url);
            console.log(666,result);

            let data = JSON.parse(result)

            //保存图片
            this.order.car_check_img.push(data.data.img)
        }

        i++;
      })
      console.log('照片列表',this.picList);
    },

    // 上传图片
    uploadFilePromise(url) {
      return new Promise((resolve, reject) => {
        uni.uploadFile({
          url: this.apiUrl + "/upload/imageOne", // 仅为示例,非真实的接口地址
          filePath: url,
          name: "file",
          formData: {
            typeEnum: "IMAGE",
          },
         header: {
             'X-CSRF-TOKEN': token.getToken('TOKEN') //自行定义token,根据接口要求是否需要加上
         },
          success: (res) => {
            resolve(res.data);

          },
        });
      });
    },

    //移除图片
    beforeRemove(index, fileList){

         // 确保索引在有效范围内
        if (index >= 0 && index < this.order.car_check_img.length) {
            // 使用 splice 方法移除 this.order.car_check_img 中的对应项
            this.order.car_check_img.splice(index, 1);
        }

        // 如果需要,您还可以从 picList 中移除对应的项
        // 假设 fileList 和 picList 是同步的,并且 fileList[index] 是要移除的文件
        if (index >= 0 && index < this.picList.length) {
            this.picList.splice(index, 1);
        }
    }
<u-upload 
    :file-list="picList" //默认显示的图片列表
    :action="url" 
    :before-upload="beforeUpload" //为图片上传之前的回调
    :before-remove="beforeRemove" //为图片删除之前的回调
></u-upload>

js方法:

    beforeUpload(index, list) {
      this.picList = []
      // console.log('list',list);
      list.map(async item => {
        this.picList.push({
          url: item.url
        })
        let result = await this.uploadFilePromise(item.url);
        console.log(result);
      })
      console.log('照片列表',this.picList);
    },

    // 上传图片
    uploadFilePromise(url) {
      return new Promise((resolve, reject) => {
        uni.uploadFile({
          url: apiUrl + "/admin/upload/imageOne", // 仅为示例,非真实的接口地址
          filePath: url,
          name: "file",
          formData: {
            typeEnum: "IMAGE",
          },
         header: {
             'X-CSRF-TOKEN': token.getToken('TOKEN') //自行定义token,根据接口要求是否需要加上
         },
          success: (res) => {
            resolve(res.data);
            console.log(res);
          },
        });
      });
    },

微信小程序用户授权获取用户位置信息
1、配置文件manifest.json,选择“源码视图”,添加配置

2、上代码

            getLocationInfo(){
                uni.getLocation({
                  type: 'gcj02',
                  success: function(res) {
                    const latitude = res.latitude; // 纬度
                    const longitude = res.longitude; // 经度

                    // 调用逆地理编码API将经纬度转换为地址
                    uni.request({
                      url: 'https://apis.map.qq.com/ws/geocoder/v1/',
                      data: {
                        location: `${latitude},${longitude}`,
                        key: '你的key' //腾讯地图开放平台上申请并获得了Web服务API密钥
                      },
                      success: function(response) {
                        const address = response.data.result.address;

                        // 在此处处理获取到的地址信息
                        console.log("在此处处理获取到的地址信息" + address);

                        this.form.get_car_address = address
                      }
                    })
                  }
                })
            }

3、如果没有key,去腾讯地图开放平台上申请并获得了Web服务API密钥
地址:https://lbs.qq.com/dev/console/home

4、常见问题
4.1 此key未开启WebserviceAPI功能

4.2 getLocation:fail the api need to be declared in the requiredPrivateInfos fie
这个问题查看第一步,没有配置manifest.json导致的

当前mybaits-plus版本为3.5.3

springboot启动报错Bean named ‘ddlApplicationRunner’ is expected to be of type ‘org.springframework.boot.Runner’ but was actually of type ‘org.springframework.beans.factory.support.NullBean’

解决:在启动类加上方法

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }


    /**
     * 解决:Bean named 'ddlApplicationRunner' is expected 的报错
     * @param ddlList
     * @return
     */
    @Bean
    public DdlApplicationRunner ddlApplicationRunner(@Autowired(required = false) List ddlList) {
        return new DdlApplicationRunner(ddlList);
    }

1、真机调试时勾选局域网模式

2、修改api接口地址为本地局域网ip地址

3、修改接口地址

4、关闭windows防火墙(重要!重要!重要)

5、手机要和电脑使用的同一个网络wifi
自行查看手机连接的wifi,查看内容ip地址是否是同一个网络段

ok,搞定

更新composer时报错:Root composer.json requires PHP extension ext-http * but it is missing from your system. Install or enable PHP’s http extension

错误原文:
Your lock file does not contain a compatible set of packages. Please run composer update.

Problem 1
Root composer.json requires PHP extension ext-http * but it is missing from your system. Install or enable PHP’s http extension.

To enable extensions, verify that they are enabled in your .ini files:
D:xxx\php\74\php.ini
You can also run php —ini inside terminal to see which files are used by PHP in CLI mode.

解决办法:

将composer.json里的”ext-http”: ““ 删除
将composer.lokc里的”ext-http”: “
“ 删除

使用uview组件tabbar底部导航栏,点击按钮实现页面切换

导航栏结构代码

<u-tabbar v-model="current" :list="list" @change="navigatorTo"></u-tabbar>

Js代码

export default {
        data() {
            return {
                current: 0,
                list: [{
                        iconPath: "home",
                        selectedIconPath: "home-fill",
                        text: '首页',
                        customIcon: false,
                        pagePath: '/pages/business/home/home'
                    },
                    {
                        iconPath: "photo",
                        selectedIconPath: "photo-fill",
                        text: '站点',
                        customIcon: false,
                        pagePath: '/pages/business/site/list'
                    }
                ],
            }
        },
        methods: {
            navigatorTo(index) {
                let url = this.list[index].pagePath
                uni.navigateTo({
                    url: url,
                })
            }
        },
    }

uniapp页面跳转方式和区别

第一:wx.navigatorTo  //新页面打开,默认会有返回按钮

第二:wx.redirectTo     //当前页面打开,默认无返回按钮

第三:wx.switchTab    //只能用于跳转到tabbar页面,并关闭其他非tabbar页面,tabbar之间做切换

第四:wx.reLaunch    //关闭所有页面,打开应用内某个页面,默认无返回按钮】

隐藏左上角返回按钮和首页按钮

onShow() {
    uni.hideHomeButton()
    //wx.hideHomeButton()
},

例如从A小程序跳转到B小程序

wx.navigateToMiniProgram({
    appId: 'xxxxx', //跳转到的小程序appid
    path: '/page/home/index/index?wxrefid=xxxxx&tab=1&appid=xxxxx', //跳转到的小程序页面地址
    //develop开发版;trial体验版;release正式版
    envVersion: 'release', 
    success(res) {
        // 打开成功
        console.log("跳转小程序成功!",res);
    } 
})

##### 第一种,点击按钮选择图片上传

<div class="avatar">
    <image mode="" :src="data.profilePhoto || '../../static/index/1.jpg'"></image>
    <text class="avatar-btn" @click="chooseImage">点击上传头像</text>
</div>


    // 选择头像
        chooseImage() {
          uni.chooseImage({
            count: 1, // 最多选择的图片数量,可以根据需求修改
            sizeType: ['original', 'compressed'],
            sourceType: ['album', 'camera'],
            success: (res) => {
              // 选择图片成功
              const tempFilePaths = res.tempFilePaths

              this.uploadAvatar( tempFilePaths[0])
            },
            fail: (err) => {
              // 选择图片失败
              console.log('选择图片失败:', err.errMsg);
            }
          })
        },
        // 上传头像
        uploadAvatar(avatar) {
          console.log('上传文件地址: ', avatar)
          uni.uploadFile({
            url: this.action, //修改成自己的接口地址
            filePath: avatar,
            name: 'file',
            header: {
              'Content-Type': 'multipart/form-data',
              'Authorization': 'Bearer ' + token.getToken('token') // 设置你需要的自定义请求头
            },
            formData: {
              // 可以添加额外的表单数据
            },
            success: res => {
              const data = JSON.parse(res.data)
              this.data.profilePhoto = data.data.url
            },
            fail: err => {

              console.log('上传失败', err)
              this.user = uni.getStorageSync('user')
            }
          })
        },

第二种,upload上传

<div class="block">
    <u-upload
    :fileList="fileList"
    @afterRead="afterRead"
    @delete="deletePic"
    name="3"
    multiple
    :maxCount="10"
    :previewFullImage="true"
    ></u-upload>
</div>


        // 删除图片
        deletePic(event) {
            this.fileList.splice(event.index, 1)
        },
        // 新增图片
        async afterRead(event) {
            // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
            let lists = [].concat(event.file)
            let fileListLen = this.fileList.length
            lists.map((item) => {
                this.fileList.push({
                    ...item,
                    status: 'uploading',
                    message: '上传中'
                })
            })
            for (let i = 0; i < lists.length; i++) {
                const result = await this.uploadFilePromise(lists[i].url)
                let item = this.fileList[fileListLen]
                this.fileList.splice(fileListLen, 1, Object.assign(item, {
                    status: 'success',
                    message: '',
                    url: result
                }))
                fileListLen++
            }
        },
        uploadFilePromise(url) {
            return new Promise((resolve, reject) => {
                let a = uni.uploadFile({
                    url: this.action,  //修改成自己的接口地址
                    filePath: url,
                    name: 'file',
                    formData: {

                    },
                    success: (res) => {
                        const data = JSON.parse(res.data)
                        this.fileListImg.push(data.data.url)
                    }
                });
            })
        },

微信小程序自定义顶部导航栏搜索框(非组件)

一、隐藏原生navigationBar

  1. 全局自定义顶部导航栏
    在app.json的“window”里添加”navigationStyle”: “custom”

    "window": {
     "navigationStyle": "custom"
    }
    
  2. 单独页面自定义顶部导航栏
    在该页面的json文件里添加”navigationStyle”: “custom”

    {
    "usingComponents":{},
    "navigationStyle": "custom"
    }
    

二、获取系统及按钮信息,详细写法,请参考:https://blog.csdn.net/YN2000609/article/details/134212825

  1. js页面
    获取系统信息并计算按钮位置信息

  2. wxml页面
    通过获取的数据编写搜索框

  3. css页面
    美化搜索框

  4. app.js页面

场景

实现

  1. 创建过滤器
    ```
    package com.bderp.config;

import com.bderp.common.TrimFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;

@Configuration
public class FilterConfig {

/**
 * 去除参数头尾空格过滤器
 *
 * @return
 */
@Bean
public FilterRegistrationBean trimFilter() {
    System.out.println("============过滤=================");
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setDispatcherTypes(DispatcherType.REQUEST);
    registration.setFilter(new TrimFilter());
    registration.addUrlPatterns("/*");
    registration.setName("TrimFilter");
    registration.setOrder(1);
    return registration;
}

}

2. 创建过滤器类

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class TrimFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    filterChain.doFilter(new TrimHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
}

@Override
public void destroy() {

}

}

3. 创建请求参数过滤类

import com.bderp.utils.JsonTrimUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class TrimHttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {

private Map<String , String[]> params = new HashMap<>();

public TrimHttpServletRequestWrapper(HttpServletRequest request) {
    // 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
    super(request);
    //将参数表,赋予给当前的Map以便于持有request中的参数
    this.params.putAll(request.getParameterMap());
    this.modifyParameterValues();
}
/**
 * 重写getInputStream方法  post类型的请求参数必须通过流才能获取到值
 */
@Override
public ServletInputStream getInputStream() throws IOException {
    System.out.println("data");
    System.out.println("aaaaaaaaaaaaS");
    //非json类型,直接返回
    if(!super.getHeader(HttpHeaders.CONTENT_TYPE).contains(MediaType.APPLICATION_JSON_VALUE)){
        return super.getInputStream();
    }
    //为空,直接返回
    String json = IOUtils.toString(super.getInputStream(), "utf-8");
    if (!StringUtils.hasLength(json)) {
        return super.getInputStream();
    }
    ByteArrayInputStream bis = null;
    try {
        bis = new ByteArrayInputStream(JsonTrimUtils.jsonTrim(json).toJSONString().getBytes());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return new MyServletInputStream(bis);
}
/**
 * 将parameter的值去除空格后重写回去
 */
public void modifyParameterValues(){
    Set<String> set =params.keySet();
    Iterator<String> it=set.iterator();
    while(it.hasNext()){
        String key= it.next();
        String[] values = params.get(key);
        for (int i = 0; i < values.length; i++) {
            values[i] = values[i].trim();
        }
        params.put(key, values);
    }
}
/**
 * 重写getParameter 参数从当前类中的map获取
 */
@Override
public String getParameter(String name) {
    String[]values = params.get(name);
    if(values == null || values.length == 0) {
        return null;
    }
    return values[0];
}
/**
 * 重写getParameterValues
 */
@Override
public String[] getParameterValues(String name) {//同上
    return params.get(name);
}

class MyServletInputStream extends  ServletInputStream{
    private ByteArrayInputStream bis;
    public MyServletInputStream(ByteArrayInputStream bis){
        this.bis=bis;
    }
    @Override
    public boolean isFinished() {
        return true;
    }

    @Override
    public boolean isReady() {
        return true;
    }

    @Override
    public void setReadListener(ReadListener listener) {

    }
    @Override
    public int read() {
        return bis.read();
    }
}

}

4. 创建过滤工具类

package com.bderp.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;

import java.util.Iterator;
import java.util.Map;

/**

  • json工具类
  • @Version 1.0
    /
    public final class JsonTrimUtils {
    /*

    • 构造器
      */
      private JsonTrimUtils() {
      }

      /**

    • 去除json值前后空格
    • @param jsonStr jsonStr
    • @return
      */
      public static JSON jsonTrim(String jsonStr) throws Exception {
      System.out.println(“JSONValidator.Type.Object”);
      System.out.println(JSONValidator.Type.Object);
      System.out.println(JSONValidator.from(jsonStr).getType());
      System.out.println(JSONValidator.from(jsonStr).getType());
      if (JSONValidator.from(jsonStr).getType() == JSONValidator.Type.Object) {
       System.out.println("============data");
       System.out.println(jsonTrim(JSONObject.parseObject(jsonStr)));
       return  jsonTrim(JSONObject.parseObject(jsonStr));
      
      }
      //前后端联调传值类型不同,及早的暴露问题,避免隐藏问题。
      throw new Exception(“非JSON参数”);
      }

// /*
//
去除json值前后空格
// @param json jsonStr
//
@return
// */
// public static JSON jsonTrim(JSON json) throws Exception {
// if (json instanceof JSONObject) {
// return jsonTrim(json);
// } else if (json instanceof JSONArray) {
// jsonTrimArray((JSONArray) json);
// return json;
// }
// throw new Exception(“非JSON参数”);
// }

/**
 * 去除value的空格
 *
 * @param jsonObject jsonObject
 * @return
 */
public static JSONObject jsonTrim(JSONObject jsonObject) {
    Iterator<Map.Entry<String, Object>> iterator = jsonObject.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, Object> next = iterator.next();
        Object value = next.getValue();
        if (value != null) {
            if (value instanceof String) {
                //清空值前后空格
                jsonObject.put(next.getKey(), ((String) value).trim());
            } else if (value instanceof JSONObject) {
                jsonTrim((JSONObject) value);
            } else if (value instanceof JSONArray) {
                jsonTrimArray((JSONArray) value);
            }
        }
    }

    return jsonObject;
}

/**
 * 清空JSONArray 值前后空格
 * @param array
 */
private static void jsonTrimArray(JSONArray array) {
    if (array.size() > 0) {
        for (int i = 0; i < array.size(); i++) {
            Object object = array.get(i);
            if (object != null) {
                if (object instanceof String) {
                    array.set(i, ((String) object).trim());
                } else if (object instanceof JSONObject) {
                    jsonTrim((JSONObject) object);
                } else if (object instanceof JSONArray) {
                    jsonTrimArray((JSONArray) object);
                }
            }
        }
    }
}

}

```

参考

https://blog.csdn.net/L_fly_J/article/details/120991367

场景

实现

  1. 创建过滤器
    ```
    package com.bderp.config;

import com.bderp.common.TrimFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;

@Configuration
public class FilterConfig {

/**
 * 去除参数头尾空格过滤器
 *
 * @return
 */
@Bean
public FilterRegistrationBean trimFilter() {
    System.out.println("============过滤=================");
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setDispatcherTypes(DispatcherType.REQUEST);
    registration.setFilter(new TrimFilter());
    registration.addUrlPatterns("/*");
    registration.setName("TrimFilter");
    registration.setOrder(1);
    return registration;
}

}

2. 创建过滤器类

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class TrimFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    filterChain.doFilter(new TrimHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
}

@Override
public void destroy() {

}

}

3. 创建请求参数过滤类

import com.bderp.utils.JsonTrimUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class TrimHttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {

private Map<String , String[]> params = new HashMap<>();

public TrimHttpServletRequestWrapper(HttpServletRequest request) {
    // 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
    super(request);
    //将参数表,赋予给当前的Map以便于持有request中的参数
    this.params.putAll(request.getParameterMap());
    this.modifyParameterValues();
}
/**
 * 重写getInputStream方法  post类型的请求参数必须通过流才能获取到值
 */
@Override
public ServletInputStream getInputStream() throws IOException {
    System.out.println("data");
    System.out.println("aaaaaaaaaaaaS");
    //非json类型,直接返回
    if(!super.getHeader(HttpHeaders.CONTENT_TYPE).contains(MediaType.APPLICATION_JSON_VALUE)){
        return super.getInputStream();
    }
    //为空,直接返回
    String json = IOUtils.toString(super.getInputStream(), "utf-8");
    if (!StringUtils.hasLength(json)) {
        return super.getInputStream();
    }
    ByteArrayInputStream bis = null;
    try {
        bis = new ByteArrayInputStream(JsonTrimUtils.jsonTrim(json).toJSONString().getBytes());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return new MyServletInputStream(bis);
}
/**
 * 将parameter的值去除空格后重写回去
 */
public void modifyParameterValues(){
    Set<String> set =params.keySet();
    Iterator<String> it=set.iterator();
    while(it.hasNext()){
        String key= it.next();
        String[] values = params.get(key);
        for (int i = 0; i < values.length; i++) {
            values[i] = values[i].trim();
        }
        params.put(key, values);
    }
}
/**
 * 重写getParameter 参数从当前类中的map获取
 */
@Override
public String getParameter(String name) {
    String[]values = params.get(name);
    if(values == null || values.length == 0) {
        return null;
    }
    return values[0];
}
/**
 * 重写getParameterValues
 */
@Override
public String[] getParameterValues(String name) {//同上
    return params.get(name);
}

class MyServletInputStream extends  ServletInputStream{
    private ByteArrayInputStream bis;
    public MyServletInputStream(ByteArrayInputStream bis){
        this.bis=bis;
    }
    @Override
    public boolean isFinished() {
        return true;
    }

    @Override
    public boolean isReady() {
        return true;
    }

    @Override
    public void setReadListener(ReadListener listener) {

    }
    @Override
    public int read() {
        return bis.read();
    }
}

}

4. 创建过滤工具类

package com.bderp.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;

import java.util.Iterator;
import java.util.Map;

/**

  • json工具类
  • @Version 1.0
    /
    public final class JsonTrimUtils {
    /*

    • 构造器
      */
      private JsonTrimUtils() {
      }

      /**

    • 去除json值前后空格
    • @param jsonStr jsonStr
    • @return
      */
      public static JSON jsonTrim(String jsonStr) throws Exception {
      System.out.println(“JSONValidator.Type.Object”);
      System.out.println(JSONValidator.Type.Object);
      System.out.println(JSONValidator.from(jsonStr).getType());
      System.out.println(JSONValidator.from(jsonStr).getType());
      if (JSONValidator.from(jsonStr).getType() == JSONValidator.Type.Object) {
       System.out.println("============data");
       System.out.println(jsonTrim(JSONObject.parseObject(jsonStr)));
       return  jsonTrim(JSONObject.parseObject(jsonStr));
      
      }
      //前后端联调传值类型不同,及早的暴露问题,避免隐藏问题。
      throw new Exception(“非JSON参数”);
      }

// /*
//
去除json值前后空格
// @param json jsonStr
//
@return
// */
// public static JSON jsonTrim(JSON json) throws Exception {
// if (json instanceof JSONObject) {
// return jsonTrim(json);
// } else if (json instanceof JSONArray) {
// jsonTrimArray((JSONArray) json);
// return json;
// }
// throw new Exception(“非JSON参数”);
// }

/**
 * 去除value的空格
 *
 * @param jsonObject jsonObject
 * @return
 */
public static JSONObject jsonTrim(JSONObject jsonObject) {
    Iterator<Map.Entry<String, Object>> iterator = jsonObject.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, Object> next = iterator.next();
        Object value = next.getValue();
        if (value != null) {
            if (value instanceof String) {
                //清空值前后空格
                jsonObject.put(next.getKey(), ((String) value).trim());
            } else if (value instanceof JSONObject) {
                jsonTrim((JSONObject) value);
            } else if (value instanceof JSONArray) {
                jsonTrimArray((JSONArray) value);
            }
        }
    }

    return jsonObject;
}

/**
 * 清空JSONArray 值前后空格
 * @param array
 */
private static void jsonTrimArray(JSONArray array) {
    if (array.size() > 0) {
        for (int i = 0; i < array.size(); i++) {
            Object object = array.get(i);
            if (object != null) {
                if (object instanceof String) {
                    array.set(i, ((String) object).trim());
                } else if (object instanceof JSONObject) {
                    jsonTrim((JSONObject) object);
                } else if (object instanceof JSONArray) {
                    jsonTrimArray((JSONArray) object);
                }
            }
        }
    }
}

}

```

第一次使用EasyWeChat微信支付SDK发现代码量很少,很简洁,但是在使用过程中也花了很多时间,遇到了很多问题

1、
第一次尝试时,发现下面的解释是当支付方式为APP时,才需要进行二次签名
//如trade_type = APP
//需要进行二次签名
所以第一次并没有进行二次签名,接口成功返回,但是一直报错支付验证签名失败

2、
尝试了几次后,进行二次签名验证再进行尝试,但是发现也是一直报错支付验证签名失败

3、之后就去微信支付接口签名校验工具,去验证签名
微信支付接口签名校验工具地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1
发现xml的验证结果是正确的

4、去百度查看别人分享的EasyWeChat使用方法,发现使用的二次加密的方法和官网的不一样,结果真的就解决了

$result = $app->jssdk->appConfig($prepayId);
官网文档写的:
(new \EasyWeChat\Payment\Jssdk\Client($app))->appConfig($result[‘prepay_id’]);

总结:官网只是简单的告诉SDK的用法,但是呢还是要结合看看自己的业务来进行调整和使用

1、第一步,安装EasyWeChat版本,本章文档使用的是4.*版本

使用 composer:

composer require overtrue/wechat:~4.0 -vvv

2、配置

use EasyWeChat\Factory; //引入sdk

$config = [
// 必要配置
'app_id'             => 'xxxxxx', //微信小程序appid
'mch_id'             => 'xxxxxx', //微信支付商户号
'key'                => 'xxxxxx', //微信支付API v2 密钥 (注意: 是v2密钥 是v2密钥 是v2密钥)
// 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
'cert_path'          => 'path/to/your/cert.pem', // XXX: 绝对路径!!!!
'key_path'           => 'path/to/your/key',      // XXX: 绝对路径!!!!
'notify_url'         => $this->request->domain() . '/index/order/payCallback',// 支付回调地址
];

$app = Factory::payment($config);

3、下单 (本章文档使用的是JSAPI)

$result = $app->order->unify([
'body' => '充值积分',
'out_trade_no' => "xxx", //订单号
'total_fee' => 1.00, //支付金额
'spbill_create_ip' => '', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
'notify_url' => $this->request->domain() . '/index/order/payCallback', // 支付回调地址
'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
'openid' => $user['openid'], //用户的openid
]);

4、获取签名,并返回给前端

if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {

$package = "prepay_id=" . $result['prepay_id']; 

//需要进行二次签名(重要!重要!重要!)
//$result = $app->jssdk->bridgeConfig($result['prepay_id'], false);
$result = $app->jssdk->appConfig($result['prepay_id']);

$time = time();
$result['timeStamp'] = "$time";
$result['signType'] = "MD5"; //默认加密方式
$result['package'] = $package;

return $this->success('成功', $result);
}

5、前端uniapp的uni.requestPayment是一个统一各平台的客户端支付API

    //拉起支付
    pay(){
        http.post('/order/payment', {order_number:"xxxx"}).then((res) => {
            let payParams = res.data
            uni.requestPayment({
                provider: 'wxpay',
                timeStamp: payParams.timeStamp,
                nonceStr: payParams.nonceStr,
                package: payParams.package,
                signType: payParams.signType,
                paySign: payParams.paySign,
                success: function (res) {
                    console.log('支付成功');
                    console.log(res);
                    uni.showToast({
                        title: '支付成功',
                        icon: "success"
                    })
                },
                fail: function (res) {
                    console.log(res);
                    console.log('支付失败');
                    uni.showToast({
                        title: '支付失败',
                        icon: "error"
                    })
                }
            });
        })
    },

6、支付回调



    //支付回调
    public function payCallback()
    {
        try{
//            $myfile = fopen(public_path()."/pay_log.txt", "w+") or die("Unable to open file!");


            $xml = file_get_contents('php://input');
            $data = $this->xmltoarrayx($xml);

//            fwrite($myfile, $xml);
//            fclose($myfile);

            if ($data == null) {
                $data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
            }

            if (empty($data) || $data == null || $data == '') {
                //阻止微信接口反复回调接口  文档地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,下面这句非常重要!!!
                //$str = '';
                //echo $str;
				$return_msg = 'OK';
				$return_code = 'SUCCESS';
				return json_encode([
					"return_msg" => $return_msg,
					"return_code" => $return_code
				]);
                exit('Notify 非法回调');
            }

            Log::info('支付回调数据 -> ' . json_encode($data));

            $out_trade_no = isset($data['out_trade_no']) && !empty($data['out_trade_no']) ? $data['out_trade_no'] : 0;

            if ($data['return_code'] == 'SUCCESS' && $data['result_code'] == 'SUCCESS') {
                // 查询订单号
                $order = OrderModel::where('uuid', $out_trade_no)->find();
                if($order){
                    //更改订单支付状态
                    $order->pay_state = 1;
                    $order->save();
					
					//更新金额等操作
			

                }
            }
			
			//回调给微信,告知接收成功
			//
            //$str = ``;
            //echo $str;
			$return_msg = 'OK';
			$return_code = 'SUCCESS';
			return json_encode([
				"return_msg" => $return_msg,
				"return_code" => $return_code
			]);
        }catch (\Exception $e){
//            $myfile = fopen(public_path()."/pay_log_error.txt", "w+") or die("Unable to open file!");
//            fwrite($myfile, $e->getMessage());
//            fclose($myfile);
            Log::error('支付回调异常 -> ' . $e->getMessage());
        }
    }
	
	
	
    // xml 转数组
    protected function xmlToArrayx($xml)
    {
        if (!$xml) {
            return false;
        }
        libxml_disable_entity_loader(true);
        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $arr;
    }

附:有什么参错上不懂的可以看官方文档
微信支付JSAPI调起支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
微信支付统一下单官方文档:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1
开发接入文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
微信支付接口签名校验工具: https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1

环境

uniapp
微信开发者工具

问题

Error: This application has not registered any plugins yet.

问题分析

1.确认该页面存在
2.确认该页面已添加到pages.json

原因

改页面调用了插件,但改插件没有相应的权限

环境

uniapp
微信开发者工具

问题

Error: This application has not registered any plugins yet.

问题分析

1.确认该页面存在
2.确认该页面已添加到pages.json

原因

pages.json中的某个页面的标签没有闭合

<view v-html="article.desc"></view>
使用v-html显示富文本编辑器的内容时,里面如果添加了缩略图图片,在微信小程序中显示时会发现由于图片太大,导致图片显示时变形

导致图片溢出

解决:可以通过设置css样式来处理

//防止富文本图片宽度溢出
if(this.article.desc !=null || this.article.desc != ""){
    this.article.desc = this.article.desc.replace(/\<img/g, '<img style="max-width:100%;height;auto" ');
}

thinkphp6 使用jwt报错
Call to undefined function sodium_base642bin()

解决:找到php.ini文件将extension=sodium前面的;号去除

保存后重启php

1、自定义按钮方式 <button open-type="share"> 或监听系统右上角的分享按钮 onShareAppMessage 进行自定义分享内容

<button open-type='share' @click="setShareId(item)" type="primary" class="button-sure" :data-item='item'>
    转发给好友
</button>

2、定义一个setShareId方法,用于接收点击的参数id

setShareId(item){
    this.share_id = item.id;
},

3、分享方法

    //分享
    async onShareAppMessage(item){
         try {
             //请求后端接口,获取token
            const result = await this.getItemSetId();

            // 拿到token后在进行分享
            return {
              title: "分享订单详情",
              path: '/pages/share/detail?token=' + result.token,
            }
          } catch (error) {
            console.error('获取token失败:', error);
            // 处理获取token失败的情况
            // 返回默认的分享链接或者其他操作
          }
    },

4、请求后台接口方法

    getItemSetId() {
      return new Promise((resolve, reject) => {
        http.get("/share/getToken", { id: this.share_id })
          .then(res => {
           // 将token作为结果传递给resolve方法
            resolve({ token: res.data });
          })
          .catch(error => {
            console.error('网络请求失败:', error);
            reject(error); // 将错误对象作为结果传递给reject方法
          });
      });
    },

这样分享后的链接页面/pages/share/detail打开后就会携带token参数了

1、把已提交到git仓库的文件或目录删除
使用以下命令将目录从Git仓库中移除:

git rm -r --cached <directory_name>

将<directory_name>替换为你要移除的目录名称。该命令将递归地移除目录及其下的所有文件,并将其从Git的缓存中删除。

2、提交更改:

git commit -m "Remove <directory_name> from Git"

场景

微信小程序开发
使用订阅消息

环境

thinkphp6
easywechat

代码

//发送消息通知模板
    public function sendMessage($openid)
    {

        $config = [
            'corp_id' => '',
            'agent_id' => '', // 如果有 agend_id 则填写
            'secret'   => '',
            // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
            'response_type' => 'array',
        ];

        $data = [
            'template_id' => "iGioueHodXKO8pahxSjQt3bU01Vq79JsjwTBS3YnfRU", // 所需下发的订阅模板id
            'touser' => $openid,     // 接收者(用户)的 openid
            'page' => '',       // 点击模板卡片后的跳转页面,仅限本小程序内的页面。
            'data' => [         // 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
                'thing3' => [
                    'value' => '小明', //客户名称
                ],
            ],
        ];

        $app = Factory::miniProgram($config);
        $app->subscribe_message->send($data);
    }

报错信息

Request access_token fail: {"errcode":41002,"errmsg":"appid missing rid: 6263c40b-6076c953-2928c53a"}

本次问题原因

缺少app_id参数

问题分析

"errcode":41002
基本可以判断,是权限验证问题,可能的原因
1、缺少:app_id、secret
2、app_id、secret错误

1、初始化git仓库

git init

2、设置仓库接受代码提交
允许远程提交代码

git config receive.denyCurrentBranch ignore

3、服务器端编辑钩子文件

vim .git/hooks/post-update

4、 post-update文件内容,当有git提交时可自动更新代码

#!/bin/sh
unset GIT_DIR
cd ..
git checkout -f

5、设置文件权限

chmod +x .git/hooks/post-update

场景

获取当前年份、月份

实现

let date = new Date()
let currentYear = date.getFullYear() //获取完整的年份(4位)
let currentMonth = date.getMonth() + 1 //获取当前月份(1-12,1代表1月)
currentMonth = currentMonth >= 10 ? currentMonth : "0" + currentMonth

场景

有时候切换底部菜单,需要带上参数

解决方案

1、切换前设置缓存,切换后到另一个页面后,清除缓存
2、自己定义一个底部菜单

项目背景

1、项目属于二开项目
2、基础功能都有
3、后端使用的fastadmin

开发中遇到的问题

1、原始系统有些功能不能正常使用,但又不能另外加费用
2、客户一开始不愿意给预付款,但又急着想完成开发
3、客户期望参考飞zhu小程序开发,一开始设计了很多功能,但是后来和客户沟通这些功能实际用不上
4、开发对前端不熟,遇到问题不能快速处理

总结

1、二开项目的开发成本需要提高一些,主要是熟悉原始系统的成本,遇到问题开发起来会很南
2、利益一开始要谈好

场景

从mysql5.6导出数据,导入到mysql5.7的数据库

问题

mysql数据导入时报Incorrect date value: '0000-00-00' for column 'date' at row

问题分析

mysql5.7以上的版本默认不允许datetime格式的数据出现’0000-00-00’的情况

问题处理

修改数据库的mysql.int参数,添加以下代码
sql_mode="NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

注意:谨慎使用清空操作

语法

删除数据:delete from 表名 where id='1';,如果数据多,会慢
清空表:truncate table 表名:速度快,清空后无法恢复
删除表:drop table if exists 表名;

使用场景

软件开发中通常情况下是不需要使用到mysql函数的。有时候需要对原始数据处理的时候就需要用到一些mysql字符串处理函数

常用字符串截取函数

  • left(str, length),从左边第一位开始截取指定长度字符串
  • right(str, length) ,从右边第一位开始截取指定长度字符串
  • substring(str, index, length),从指定开始位置截取指定长度字符串,index从1开始,如果是负数,表示用右开始数
  • substring_index(str, dim, length) ,从指定字符位置开始截取指定长度字符串

微信申请退款,报错证书验证失败

刚开始百度时,大部分都是在说配置错误导致的
后面在耐性仔细的查看的微信的说明文档后发现是需要去微信支付下载一个申请下载API证书
微信支付退款文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3


下载后,在退款接口中,请求微信接口时需要带上证书即可
注意:
证书pkcs12格式,证书pem格式
部分开发语言和环境,不能直接使用p12文件,而需要使用pem(列如PHP使用的是pem)

今天拉取项目代码时,更新maven发现无法更新,然后查看错误发现pom.xml提示错误和警告信息

解决:根据提示,将项目所在目录添加进入系统的排除项中

进入到mysql安装目录的bin目录下,运行cmd
输入mysql_upgrade -uroot -p,输入密码
然后重启mysql即可

问题:图标和文字在一个盒子内居中显示。

在小程序中,可以使用flex布局将图标和文字放在一个盒子中,并使它们居中显示。首先,将图标和文字放在一个view组件内,然后使用flex布局的相关属性实现居中对齐。可以通过设置view组件的display属性为flex,然后设置justify-content和align-items属性为center,将图标和文字水平和垂直居中显示。

示例:

<view style="display: flex; justify-content: center; align-items: center;">
  <u-icon name="scan" color="#fff" size="50"></u-icon>
  <text>文字内容</text>
</view>

问题:为什么在css里使用background-image插入背景图片时,浏览器没有任何反应?

错误写法:

  1. 插入背景图片的路径写错了。
    background-image: url(/img/科技.jpg);
    

正确写法:

background-image: url('./img/科技.jpg');

问题:背景图片太大显示不全。

解决思路:

  1. 通过设置div的大小大于背景图片的大小,使背景图片完全显示;

    body {
    width: 200px;
    height: 200px;
    ckground-image: url('./img/科技.jpg');
    }
    
  2. 使用background-size属性将背景图片的大小设置为小于div的大小。

    body {
     background-image: url('./img/科技.jpg');
     background-size: cover;
    }
    

需求:前端通过一个输入框,既可以查询学号又可以查询姓名
后端:通过或条件查询

//可以根据学号和姓名模糊搜索
        if(student.getStudentNumber() != null && !student.getStudentNumber().equals("")) {
            lqw.lambda().or(l -> {
                l.like(Student::getStudentNumber, student.getStudentNumber());
            }).or(l -> {
                l.like(Student::getName, student.getStudentNumber());
            });

            student.setStudentNumber(null);
        }

问题

渲染城市列表,卡顿

原因

按钮用的是u-view的组件,700个城市,就渲染了700次,导致页面加载慢的。

问题分析思路

减少渲染内容,查看是否正常。正常情况下渲染几百个div应该不会有什么影响

问题分析过程

  1. 因为是多层渲染,先只渲染第一层,看是否正常
  2. 只渲染第一层循环的情况下,正常
  3. 渲染第二场循环,异常
  4. 渲染第二层,只打印城市,正常
  5. 分析原因可能是u-button是组件,组件内标签较多导致

申请流程:

1、进到微信公众平台,点一下“点击注册”,挑选账号申请种类“小程序”,填好微信小程序用户信息,包含电子邮箱、登陆密码等。
2、登录到相对的电子邮箱激话账户。
3、激话 微信小程序 后,挑选“主体类型”。
4、申请注册好以后,就可以用新的微信小程序账户密码登陆后台管理,在【设置】里填好微信小程序的名字、头像、服务品类等信息内容,随后等候审批就可以。需要注意的是,如果你的服务类目与实际不符,那么是无法通过审核的。

需要客户提供的信息:

一、小程序信息:

  1. 小程序名称。
  2. 小程序简称(选填)。
  3. 小程序头像(矩形、圆形)。
  4. 向程序介绍。

二、小程序类目:

  1. 小程序的服务类目,设置主营类目。

三、小程序备案:

问题:warning: in the working copy of ‘unpackage/dist/dev/mp-weixin/app.js’, LF will be replaced by CRLF the next time Git tou ches it。

问题详情链接:https://blog.csdn.net/weixin_55252589/article/details/129017650

解决问题:
情况一:windows用户:

git config --global core.autocrlf true
#提交时转换为LF,检出时转换为CRLF:

解释:CR/LF是不同操作系统上使用的换行符:

  • CR(CarriageReturn回车’\r’):回到一行的开头,ASCII代码是13
  • LF(LineFeed换行’\n’):另起一行,ASCII代码是10

应用情况:

  • Dos和Windows平台: 使用回车(CR)和换行(LF)两个字符来结束一行,回车+换行(CR+LF),即“\r\n”;所以我们平时编写文件的回车符应该确切来说叫做回车换行符。
  • Mac 和 Linux平台:只使用换行(LF)一个字符来结束一行,即“\n”;