IT小白的第一个微信小程序(即刻翻译)

第一次尝试写文章,文笔可能不好,请见谅;

  •  自学过一个月的PHP(从零开始);
  • 自学过一个月的Web前端知识(从零开始,html+css+js);
  • 自学一个月的Centos操作系统(从零开始,本人英语极差,经常需要有道翻译~);

因为即将顶岗实习,所以决定撸一个实际上线的小程序(即刻翻译);

嗯......想说明的一点是,由于我审美观确实不咋地,所以UI界面非常丑(请不要介意!);


小程序思路:

小程序动画界面:

1. onLoad: 关闭调试接口,用户点击是否授权个人信息;

2. onShow:判断本地缓存是否存在Token,如未存在则调用 user 接口获取Token并缓存于本地;

3.做完动画跳转到翻译界面;


小程序翻译界面:

  1. Picker的Change事件;
  2. 模拟节流函数防止用户多次点击(throttle);
  3. 点击翻译时判断input的值是否为空或者是纯空格;
  4. 红色圆×的点击事件:清除input;
  5. 翻译按钮的wx.request请求(需要翻译的内容与目标语种);
  6. 翻译成功后将返回的dst显示在最下面的scroll-view;




PHP:

框架使用的ThinkPHP5.1(第一次接触的php框架);


验证层(validate):

 1.结构:

 2.代码:

BaseValidate.php:

use app\lib\exception\ParameterException;
use think\Validate;

class BaseValidate extends Validate
{ 
   public function goCheck()
    { 
       //对传入的所有参数做校验 

      获取请求的所有参数;       
      $params = \request()->param();  

      所有请求做验证
      $result = $this->batch()->check($params);

      如果不为true,抛出参数错误异常       
      if(!$result)
        {throw new ParameterException(['msg'=>$this->error*]);} 
      else
        {return true;}
     }
    
    public function isNoEmpty($value,$rule='',$data='',$field='')   
     { 
        如果值为空,直接返回false;       
        if(empty($value))        
            {return false;}
        else
            {return true;}    
      }
}


定义一个BaseValidate继承自TP的的Validate;
定义一个方法用来做requset请求(GET,POST,DELETE....)的参数验证;
定义方法 isNoEmpty(验证规则,验证参数不为空);
复制代码


CacheClean.php:

class CacheCleaner extends BaseValidate
{    
    protected $rule=[        'AdministratorKey'=>'require|isNoEmpty'    ];    
    protected $message=[        'AdministratorKey'=>'请携带正确的管理员密钥'    ];
}



定义类 CacheClearner继承自BaseValidate,管理员用来清除Token文件;复制代码

Token.php:

class Token extends BaseValidate
{    
    protected $rule =[        'code'=>'require|isNoEmpty'    ];    
    protected $message=[        'code'=>'code必须输入且不能为空'    ];
}



定义类 Token 继承自BaseValidate;


这里的Code需要传入的是 wx.login返回的Code码 
(用户登录凭证(有效期五分钟)。
开发者需要在开发者服务器后台调用 api,
使用 code 换取 openid 和 session_key 等信息);复制代码

Translate.php:

class Translate extends BaseValidate
{    
    protected $rule=[        'token'=>'require|isNoEmpty',        'q'=>'require|isNoEmpty',        'from'=>'require|isNoEmpty',        'to'=>'require|isNoEmpty',    ];    
    protected $message=[        'token'=>'token必须输入且不能为空',        'q'=>'q必须输入且不能为空',        'from'=>'from必须输入且不能为空',        'to'=>'to必须输入且不能为空',    ];
}

定义类Translate 继承自BaseValidate;
验证token,验证传递来的q(被翻译文本),from(来源语种),to(目标语种)复制代码



服务层(service):

1.结构:


1.代码:

Token.php:

use app\lib\exception\TokenException;
class Token
{    
        /**     
         * 根据token_salt和随机字符串生成32位MD5字符串;    
         * @return string     
         */    
        public static function generaeToken()   
        {        
            //32个字符组成一组随机字符串   

             生成一段随机字符串(getRandChar定义在common公共文件里面);    
            $randChars = getRandChar(32);
            
            盐写在配置文件里.
            $salt = config('token_salt');
       
            返回MD5(随机字符串+盐)的 Token;
            return md5($randChars . $salt);   
          }  

         /**     
          * 检验cache缓存中是否存在传递来的token     
          * @throws TokenException     
          */    
        public static function needToken()    
        {   
            获取本次请求的token;
            $token = request()->param('token');        
            

            如果缓存文件中不存在传来的token,抛异常
            $result = cache($token);       
            if (!$result){            
            throw new TokenException();       
            }    
        }
}


复制代码

Translate.php:

偷懒使用百度写好的php文件(很容易理解,不过为了快偷懒了......);

use app\lib\exception\BaiduException;
class Translate
{    
    protected $query;   
    protected $from;    
    protected $to;    


/**    
 * 构造 传递q ,from .to     
* Translate constructor.     
* @param $query     
* @param $from     
* @param $to     
*/    
    public function __construct($query,$from,$to)    
    {        
        $this->query=$query;        
        $this->from=$from;        
        $this->to=$to;    
    }    
/**     
* 主方法     
* @return bool|mixed     
*/    
    public function translate()   
    {        
        $args = array('q' => $this->query,'appid' => config('Bapp_id'),'salt' => config('B_salt'), 'from' => $this->from,'to' => $this->to,);
        $args['sign'] = $this->buildSign($this->query, config('Bapp_id'), $args['salt'], config('Bapp_secret'));        
        $ret = $this->call(config('Blogin_url'), $args);       
        $ret = json_decode($ret,true);       
        $this->checkApiHasError($ret);        
        return  $this->RecombinedData($ret);    
    }   

    
    /**     
    * 检测接口是否调用失败     
    * @param array $array     
    * @throws BaiduException     
    */    
    public function checkApiHasError(array $array)
    {        
        if(array_key_exists('error_code',$array)){throw new BaiduException(['msg'=>$array['error_msg'],'errorCode'=>$array['error_code']]);
    }    
    } 
   
    /**     
    * 生成签名    
    * @param $query     
    * @param $appID     
    * @param $salt     
    * @param $secKey     
    * @return string     
    */    
    public function buildSign($query, $appID, $salt, $secKey)
    {        
        $str = $appID . $query . $salt . $secKey;        
        $ret = md5($str);        
        return $ret;    
    }   


    /**     
    * 发起请求     
    * @param $url     
    * @param null $args     
    * @param string $method     
    * @param int $testflag     
    * @param int $timeout     
    * @param array $headers     
    * @return bool|mixed     
    */    
    public function call($url, $args=null, $method="post", $testflag = 0, $timeout = 10, $headers=array())    
    {        
        $ret = false;        
        $i = 0;        
        while($ret === false)
        {            
        if($i > 1) break;            
        if($i > 0){sleep(1);}            
        $ret = $this->callOnce($url, $args, $method, false, $timeout, $headers); $i++;}        
        return $ret;   
    }  

    /**     
    * 发起请求,判断是post方式还是get方式     
    * @param $url     
    * @param null $args     
    * @param string $method     
    * @param bool $withCookie     
    * @param int $timeout     
    * @param array $headers     
    * @return mixed     
    */   
    public function callOnce($url, $args = null, $method = "post", $withCookie = false, $timeout = 10, $headers = array())
    {
        $ch = curl_init();
        if ($method == "post")
        {
            $data = $this->convert($args);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_POST, 1);
        } else{
            $data = $this->convert($args);
            if ($data)
            {
            if (stripos($url, "?") > 0) {$url .= "&$data";} else{$url .= "?$data";}            
            }        
        }  
     
     curl_setopt($ch, CURLOPT_URL, $url);       
     curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);     
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    
     if (!empty($headers))  
     {          
         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);  
     }        
    if ($withCookie) 
     {   
         curl_setopt($ch, CURLOPT_COOKIEJAR, $_COOKIE);     
     }       
     $r = curl_exec($ch);
     curl_close($ch);
     return $r;    

    }  


    /**     
    * URL encode 各个字段     
    * @param $args     
    * @return string     
    */    
    public function convert(&$args)
    {
        $data = '';
        if (is_array($args))
        {
            foreach ($args as $key => $val)
            {
                if (is_array($val))
                {
                    foreach ($val as $k => $v)
                    {
                        $data .= $key . '[' . $k . ']=' . rawurlencode($v) . '&';
                    }                
                 } else{
                    $data .= "$key=" . rawurlencode($val) . "&";
                 }
            }           
           return trim($data, "&");
        }
        return $args;
    }     


    /**     
    * 重组数据     
    * @param $array     
    * @return array     
    */    
    public function RecombinedData($array)
    {
        $trans_result = $array['trans_result'];        
        $trans_result = $trans_result[0];        
        $src = $trans_result['src'];        
        $dst = $trans_result['dst'];        
        unset($trans_result);        
        return $data = ['from'=>$array['from'],'to'=>$array['to'],'src'=>$src,'dst'=>$dst];
    }

}复制代码


UserToken.php:

use app\lib\exception\WeChatException;
class UserToken extends Token{
    protected $code;    
    protected $wxAppID;    
    protected $wxAppSecret;    
    protected $wxLoginUrl; 

   
    /**     
    * 构造 传入小程序code     
    * UserToken constructor.    
    * @param $code     
    */    
    public function __construct($code)    
    {   
        wx.login返回的Code     
        $this->code = $code;

        小程序开发者的app_id        
        $this->wxAppID = config('app_id');

        小程序开发者的app_secret         
        $this->wxAppSecret = config('app_secret');
        
        把三个变量依次写入login_url中        
        $this->wxLoginUrl = sprintf(config('login_url'), 
        $this->wxAppID, $this->wxAppSecret, $this->code);    
    }    



    /**     
    * 主方法     
    * @return string     
    * @throws WeChatException     
    */    
    public function get()   
    { 
        封装curl在common.php公共文件中(这里就不贴出来);     
      $result = curl_get($this->wxLoginUrl);   
      
        返回结果json转数组;    
      $wxResult = json_decode($result, true); 
        
        如果结果为空,抛异常       
      if (!$wxResult){throw new Exception('获取session_key及openID时异常,微信内部错误');} 
        
        如果数组索引存在errcode,抛异常,否则生成令牌写入缓存并返回令牌      
      if (array_key_exists('errcode', $wxResult))       
      {$this->processLoginError($wxResult);} 
      else      
      {return $this->grantToken($wxResult);}    
    }    




    /**     
    * 生成令牌写入缓存并返回令牌     
    * @param $wxResult     
    * @return string     
    */    
    private function grantToken($wxResult)
    {        
      //生成令牌 准备缓存数据 写入缓存        
      //把令牌返回给客户端        
      //key :令牌        
      //value:wxResult;
        
      $token=$this->savaToCache($wxResult);        
      return $token;    
    }    


    /**     
    * 写入缓存  
    * @param $wxResult     
    * @return string     
    */    
    private function savaToCache($wxResult)
    {   
        键为token;
        $key=self::generaeToken();  
        
        值为openid等等      
        $value=json_encode($wxResult);    

        缓存文件过期时间为0(永不过期);    
        $expire_in=0;  
        
        写入缓存      
        $requst=cache($key,$value,$expire_in);  
    
        写入不成功抛异常      
        if(!$requst){throw new TokenException(['msg'=>'服务器缓存异常','errorCode'=>10005]);}
        
        返回key(token);        
        return $key;    
    }    


    /**     
    * 抛出code已被使用或是无效的code 的错误     
    * @param $wxResult     
    * @throws WeChatException     
    */    
    private function processLoginError($wxResult)   
     {        
    throw new WeChatException(['msg' => $wxResult['errmsg'],'errorCode' => $wxResult['errcode']]);    
    }
}复制代码


控制器层(Controller):

1.结构:



1.代码:

BaseController.php:

use think\Controller;use app\api\service\Token as TokenService;
class BaseController extends Controller
{    
    验证Token
    public function checkHaveToken()    
    {        
    TokenService::needToken();    
    }
}

定义BaseController继承自TP5的Controller
复制代码

Token.php:

use app\api\service\UserToken;
use app\api\validate\CacheCleaner;
use app\api\validate\Token as TokenValidate;
use app\lib\exception\ParameterException;
use think\facade\Cache;use think\facade\Request;
class Token extends BaseController{    
//根据客户端传来的code 生成token并返回    
    public function getToken()    
    {        
    //验证        
    (new TokenValidate())->goCheck();
    //逻辑        
    $token = (new UserToken(Request::param('code')))->get();
    //返回        
    return ['token' => $token];    
    }    


    //测试接口    
    public function cleanAllCache()    
    {
    //验证        
    (new CacheCleaner())->goCheck();  
    //逻辑      
    if(!(Request::get('AdministratorKey')===config('app.adminKey')))     
   {throw new ParameterException(['msg'=>'请携带正确的管理员密钥']);}
    
    Cache::clear();
    //返回
    return '清除缓存文件成功';
    }
}复制代码

Translate.php:

use app\api\validate\Translate as TranslateValidate;
use app\api\service\Translate as TranslateService;
use think\facade\Request;
class Translate extends BaseController
{    
    //前置操作    
    protected $beforeActionList=['checkHaveToken'=>['only'=>'translate']];    

    //根据客户端传来的token做检验,检验成功则调用百度翻译接口并返回接口数据给客户端    
    public function translate()    
    {
    //验证        
    (new TranslateValidate())->goCheck();        
    //逻辑        
    $res=(new TranslateService(Request::param('q'),Request::param('from'),Request::param('to')))->translate();       
     //返回        
    return $res;    
    }
}复制代码



异常(Exception):

1.结构:

2.代码:

ExceptionHandler.php:

use think\exception\Handle;
use think\Log;
class ExceptionHandler extends Handle
{  
  
    /**    
    * 自定义全局异常处理     
    */    
    private $code;    
    private $msg;    
    private $errorCode; 
   
    /**     
    * 根据异常类型判断是否写入日志 并返回客户端当前请求的url路径     
    * @param \Exception $e     
    * @return \think\Response|\think\response\Json     
    */    
    public function render(\Exception $e)    
    {        
        if ($e instanceof BaseException)        
        {            
            //如果是自定义的异常            
            $this->code = $e->code;            
            $this->msg = $e->msg;            
            $this->errorCode = $e->errorCode;        
        } else{            
            return parent::render($e);        
        }        
        $result = ['msg' => $this->msg,'error_code' => $this->errorCode,'request_url' => \request()->url()];        
        return json($result, $this->code);    
    }    


    /**     
    * 写入错误日志     
    * @param \Exception $e     
    */    
    public function recordErrorLog(\Exception $e)
    {        
        Log::init(['type' => 'File','path' => LOG_PATH,'level' => ['error']]);        
        Log::record($e->getMessage(), 'error');    
    }


}复制代码


BaseException.php:

use think\Exception;
class BaseException extends Exception{    
    //HTTP状态码    
    public $code = 400;    
    //错误信息    
    public $msg = '错误';    
    //自定义错误码    
    public $errorCode = 10000;    

    /**     
    * 根据错误生成错误http状态码,错误信息,和错误码     
    * BaseException constructor.     
    * @param array $params     
    */    
    public function __construct($params = [])    
    {        
        if(!is_array($params))        
        {            
            return ;        
        }        
        if(array_key_exists('code',$params)){$this->code=$params['code'];        }        
        if(array_key_exists('errorCode',$params)){$this->errorCode=$params['errorCode'];}        
        if(array_key_exists('msg',$params)){$this->msg=$params['msg'];}    
    }


}



定义BaseException继承自TP5的Exception复制代码

BaiduException.php:

class BaiduException extends BaseException
{    
    public $code=401;    
    public $msg='接口调用错误啊我的天';    
    public $errorCode=10000;
}复制代码

WeChatException.php:

class WeChatException extends BaseException
{   
    public $code = 400;    
    public $msg = '微信服务接口调用失败';    
    public $errorCode = 999;
}复制代码

TokenException.php:

class TokenException extends BaseException
{    
    public $code=401;    
    public $msg='Token过期或无效Token,请重新获取';    
    public $errorCode=10000;
}复制代码

ParameterException.php:

class ParameterException extends BaseException
{   
    public $code = 400;    
    public $msg = '参数错误';    
    public $errorCode = 10000;
}复制代码



公共文件(common.php):

    /**
    * 封装http请求 
    * @param $url 
    * @param int $httpCode 
    * @return mixed 
    */
    function curl_get($url, $httpCode = 0)
    {
        $ch = curl_init();    
        curl_setopt($ch, CURLOPT_URL, $url);    
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    
        //不做证书校验,部署在Linux环境下请改为true    
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);    
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);    
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);   
        $file_contents = curl_exec($ch);    
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);    
        curl_close($ch);    
        return $file_contents;
    }


    /** 
    * 生成随机字符串 
    * @param $length 
    * @return null|string 
    */
    function getRandChar($length)
    {    
        $str = null;    
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";    
        $max = strlen($strPol) - 1;    
        for ($i = 0; $i < $length; $i++)    
        {        
            $str .= $strPol[rand(0, $max)];    
        }    
            return $str;
    }复制代码


最后把项目部署到服务器上(我在阿里云购买的学生机和域名);

中间还遇到各种坑.(搭建环境,配置ssh证书等等);

反正很麻烦就对啦.



嗯...差不多就是这样,献丑了,嘻嘻.

                                                                                                     _______   陈三好

转载于:https://juejin.im/post/5afeea02f265da0b702628a1

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值