澳门新葡亰娱乐官网使用dedecms中常见错误提示及解决办法(一)

澳门新葡亰娱乐官网 3

分类信息有效期设置,如下图:

目标:

了解protobuf是如何做协议兼容的。

在使用 dedecms
做网站时,常常会遇到一些棘手的问题,比如:页面图片不显示(src
的地址不对)等等。

第一步:增加字段gqtime类型选择日期。

问题:

在protobuf中,是怎么做到新旧协议传输的兼容的,比如:(问题一)在新的协议里面增加了一个字段,传输到另一方是如何解码的?(问题二)又比如在新的协议里面删除了一个字段,传输到另外一方是解码的?(以下为了方便说明,使用新协议的一方为服务端,旧协议一方为客户端)


  1. 更新网站时错误

投稿表单替换html代码(增加字段时请留空)内容修改为:

问题一:在新的协议里增加了一个字段,使用旧协议的客户端是如何解码的?

测试方式:首先在服务端编写一个proto文件,拷贝一份proto文件到客户端。然后修改服务端的proto文件增加一个字段,重新生成代码,客户端还是使用原来的proto文件和代码。

问题:Call to a member function GetInnerText() on a
non-object(在一个非对象类型上调用成员函数 GetInnerText())。

select name=gqtime id=gqtimeoption value=?echo date(Y-m-d,strtotime(+7day)); ??=DoReqValue($tbname,'gqtime',stripSlashes($r[gqtime]))?7天后过期/optionoption value=?echo date(Y-m-d,strtotime(+1month)); ??=DoReqValue($tbname,'gqtime',stripSlashes($r[gqtime]))?一个月后过期/optionoption value=?echo date(Y-m-d,strtotime(+3month)); ??=DoReqValue($tbname,'gqtime',stripSlashes($r[gqtime]))?三个月后过期/optionoption value=?echo date(Y-m-d,strtotime(+6month)); ??=DoReqValue($tbname,'gqtime',stripSlashes($r[gqtime]))? selected六个月后过期/optionoption value=?echo date(Y-m-d,strtotime(+20year)); ??=DoReqValue($tbname,'gqtime',stripSlashes($r[gqtime]))?长期有效/option/select

步骤一:编写proto文件

带着这个问题,我们编写一个例子:
定义我们的proto文件PersonMsg.proto

syntax ="proto3";

package com.simple;

option java_package="com.simple";
option java_outer_classname="PersonMsg";

message Person{
    string name=1;
    int32 age=2;
}

原因:出现这个问题,是因为自定义了内容模型,这个内容模型里有图片字段。当我们去生成网站时,更新网站就会提示此错误。

第二步:打开e/class/connect.php文件,找到
//栏目链接。在其上面一行加入如下代码:

步骤二:拷贝proto文件到客户端。

这时候客户端和服务端都有一份proto文件

解决:打开 includetaglibchannelimg.lib.php 文件,将
$innerTmp =
$arcTag->GetInnerText(); 更改为 $innerTmp = ($arcTag==””) ? trim($arcTag) :
trim($arcTag->GetInnerText()); 我的版本是 V5.7-UTF8-SP1,在第 51
行。

//时间 $odate = round(((strtotime($r[gqtime])-strtotime(date('Y-m-d')))/86400),0); if ($odate0) { $diffTime = ''; // } else if ($odate==0) { $diffTime = '今天到期 '; } else { $diffTime = 'span class=expire已过期/span '; } $listtemp = str_replace ('[!--diffTime--]', $diffTime, $listtemp);

步骤三:调用protoc命令生成java代码

澳门新葡亰娱乐官网,因为我的服务端和客户端都是使用java语言,所以都生成为java代码。(这里代码就不在贴出)

 

第三步:信息调用:

步骤四:在服务端的proto文件中增加字段

在这里我们增加一个email的字段

syntax ="proto3";

package com.simple;

option java_package="com.simple";
option java_outer_classname="PersonMsg";

message Person{
    string name=1;
    int32 age=2;
    string email=3;//增加的字段
}

然后我们还是调用protoc命令重新生成服务端的协议代码。

2.
网页中图片不显示

列表页调用:[!–diffTime–]

步骤五:编写测试代码,创建使用新协议的Person对象,并将对象序列化到文件中。

@Test
    public void testSerilize() throws IOException {
        Person.Builder builder = Person.newBuilder();

        builder.setName("xiaoshan");
        builder.setAge(20);
        builder.setEmail("xxxxxxs@163.com");

        Person person =builder.build();

        byte[] byteArray = person.toByteArray();

        FileOutputStream outstream = new FileOutputStream(new File("Person.txt"));

        outstream.write(byteArray);
        outstream.close();
    }

问题:图片 src
地址显示不对,如:{dede:img text=‘‘ width=‘270‘
height=‘129‘} /uploads/161130/1-161130110AW61.jpg{/dede:img}
。当将地址换成 网址+ /uploads/161130/1-161130110AW61.jpg
时,能显示之前上传的图片。

内容页引用JS:

步骤六:在客户端读取Person.txt文件,并反序列化成Person对象。

    @Test
    public void testDeserialize() throws Exception{
        FileInputStream inputStream = new FileInputStream(new File("Person.txt"));

        Person person = Person.parseFrom(inputStream);
        inputStream.close();
        assertEquals(person.getName(),"xiaoshan");
        assertEquals(person.getAge(),20);
        //旧proto文件里面没有新加的email字段,所以生成的java代码里面也没有

    }

运行junit,测试是ok的。
接下来的问题是,protobuf是如何做到的?
我们猜想,知道类型和长度我们就可以知道如何跳过这些字段了。
下面我们介绍protobuf的做法:

private Person(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      this();
     ...........    
      try {
        boolean done = false;
        while (!done) {
          int tag = input.readTag();
          switch (tag) {
            case 0:
              done = true;
              break;
            default: {
              if (!parseUnknownFieldProto3(
                  input, unknownFields, extensionRegistry, tag)) {//这里是处理未知字段的
                done = true;
              }
              break;
            }
            case 10: {
              java.lang.String s = input.readStringRequireUtf8();//序列化name字段

              name_ = s;
              break;
            }
            case 16: {

              age_ = input.readInt32();//序列化age字段
              break;
            }
          }
        }
........

这里关键的是parseUnknownFieldProto3方法,传递了stream和一个unknownField的builder。

  protected boolean parseUnknownFieldProto3(
      CodedInputStream input,
      UnknownFieldSet.Builder unknownFields,
      ExtensionRegistryLite extensionRegistry,
      int tag)
      throws IOException {
    if (input.shouldDiscardUnknownFieldsProto3()) {//这个地方是跳过这个字段,而不把值存放到unknownFieldSet中
      return input.skipField(tag); //根据key中的类型和长度跳过字节
    }
    return unknownFields.mergeFieldFrom(tag, input);
  }

我们继续看下input.skipField的内容

@Override
    public boolean skipField(final int tag) throws IOException {
      switch (WireFormat.getTagWireType(tag)) {
        case WireFormat.WIRETYPE_VARINT:
          skipRawVarint();
          return true;
        case WireFormat.WIRETYPE_FIXED64:
          skipRawBytes(FIXED64_SIZE);
          return true;
        case WireFormat.WIRETYPE_LENGTH_DELIMITED:  //我们的例子是增加string类型的email,所以走这个判断
          skipRawBytes(readRawVarint32());
          return true;
        case WireFormat.WIRETYPE_START_GROUP:
          skipMessage();
          checkLastTagWas(
              WireFormat.makeTag(WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP));
          return true;
        case WireFormat.WIRETYPE_END_GROUP:
          return false;
        case WireFormat.WIRETYPE_FIXED32:
          skipRawBytes(FIXED32_SIZE);
          return true;
        default:
          throw InvalidProtocolBufferException.invalidWireType();
      }
    }

如我们所料,根据key中的类型做相应的处理。如我们例子中新增加的email是string类型,所以走的是
WireFormat.WIRETYPE_LENGTH_DELIMITED判断,string类型的序列化格式是:key+length+value,
所以要调用readRawVarint32读取string的长度,后面再调用
skipRawBytes跳过即可。

原因:出现这个问题,是因为自定义了内容模型,这个内容模型里有图片字段。并且用的是图片,并非图片(仅网址)。

script language=javascript src=images/date.js/script 
注意:

在proto2中,序列化到未知的字段都会同意的存放到unknowField中,但是proto3不会保证这一点,如上例中未知的字段被放弃了,查看源码可知在proto3中CodedInputStream中增加了explictDiscardUnknownFields字段控制是放弃还是存放到unknowField中。所以在proto3中不要太依靠unknownField做操作。

剩下的问题二就留给读者自己思考吧!(答案是删除的字段不会被序列化,所以那边也读不到,具体查看PersonMsg中的gerSerializedSize方法)

解决:打开
includeextend.func.php
文件。这个文件就是系统预留的自定义函数接口文件,主要用于二次开发用的。在该文件最后加上如下代码:

在需要显示的地方调用:

function GetOneImgUrl($img,$ftype=1){  
    if($img <> ''){  
        $dtp = new DedeTagParse();  
        $dtp->LoadSource($img);  
        if(is_array($dtp->CTags)){  
            foreach($dtp->CTags as $ctag){  
                if($ctag->GetName()=='img'){  
                    $width = $ctag->GetAtt('width');  
                    $height = $ctag->GetAtt('height');  
                    $imgurl = trim($ctag->GetInnerText());  
                    $img = '';  
                    if($imgurl != ''){  
                        if($ftype==1){  
                            $img .= $imgurl;  
                        }  
                        else{  
                            $img .= '<img src="'.$imgurl.'" width="'.$width.'" height="'.$height.'" />';  
                        }  
                    }  

                }  
            }  
        }  
    $dtp->Clear();  
    return $img;  
    }  
}
scriptcheck_tdate('[!--gqtime--]')/script

然后是调用该图片的代码也要改变:

date.js 文件代码如下:

列表页和首页调用方法:

// JavaScript Documentfunction check_tdate(odate){ var checkArray= new Array() ;//nowArray = odate.split( );checkArray = odate.split(-); checkDate = new Date(checkArray[0],checkArray[1],checkArray[2]);var nowTime = new Date();// 现在时间var the_year = nowTime.getYear(); var the_month = nowTime.getMonth() + 1; var the_day = nowTime.getDate();nowTime = new Date(the_year,the_month,the_day); var thesecond = 24 * 60 * 60 *1000 ; var diffTime = (nowTime - checkDate)/thesecond;//计算天数if (diffTime0){myreturn =div style='position:absolute;z-index:100;margin-left:150px;'img src=../../../images/guoqi.gif/div;}else if (diffTime==0){myreturn = '';}else {diffTime=0-diffTime;myreturn = '';}//alert(myreturn); document.write(''+myreturn+'')}

[field:bigpic
function=’GetOneImgUrl(@me,0)’/]
调用图片的信息,自动调用宽度和高度(已包含Html代码的<img
/>)

已过期图片:

[field:bigpic function=’GetOneImgUrl(@me,1)’/]
只调用图片地址,一般可用于背景图嵌套

内容页调用方法:

{dede:field name=’bigpic’ function=’GetOneImgUrl(@me,1)’/}

对应的,在添加图片的字段时,选择仅网址.

 

3.
增加用户时,提示用户名已存在

问题:在用户组里,删除用户后,重新添加时,提示用户名已经存在。

澳门新葡亰娱乐官网 1

原因:当添加用户后,在会员中心中可以看到,该用户也被添加进会员列表了。

澳门新葡亰娱乐官网 2

解决:删除添加的用户后,同时也要删除会员中心得注册会员列表里的该会员。

澳门新葡亰娱乐官网 3

 

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图