posts - 77, comments - 54, trackbacks - 0, articles - 0
  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
我在2005上研究了好长时间, 才弄出来个简单的鹰眼,与大家分享,我的设计思路是将后台设置两个map ,map1和map2,map1为主地图,map2为鹰眼地图,但是map2没有MapControl,定义一个实现类继承于MapBaseCommand,将map1.Bounds的矩形在map2上转换为System.Drawing.Rectangle,之后将这个Rectangle的左上坐标和width,height传到客户端,应用JS进行客户端绘图,在客户端加入一个Div,Div里放置一个IMG,如下为部分代码:
自定义类:
  1using System;
  2using System.Collections;
  3using System.Drawing;
  4using System.IO;
  5using System.Web;
  6using System.Web.UI.WebControls;
  7using System.Web.UI;
  8using MapInfo.Mapping;
  9using MapInfo.Data;
 10using MapInfo.WebControls;
 11
 12
 13namespace CustomWebTools
 14{
 15    /// <summary>
 16    /// Info command for InfoWebTool.
 17    /// </summary>

 18    [Serializable]
 19    public class Info : MapInfo.WebControls.MapBaseCommand
 20    {        
 21        /// <summary>
 22        /// Key to be used to get the pixel tolerance parameter value from the URL.
 23        /// </summary>

 24        protected const string PixelToleranceKey = "PixelTolerance";
 25        protected const string InfoCommand = "Info";
 26        
 27
 28        /// <summary>
 29        /// Constructor for Info class
 30        /// </summary>

 31        public Info()
 32        {
 33            Name = InfoCommand;
 34        }

 35
 36        /// <summary>
 37        /// Override the Execute method in MapBasicCommand class to not save state, because
 38        /// for info tool, which does not change map state, so there is no need to save map state.
 39        /// </summary>

 40        public override void Execute()
 41        {
 42            
 43            StateManager sm = StateManager.GetStateManagerFromSession();
 44            if (sm == null
 45            {
 46                if(StateManager.IsManualState())
 47                {
 48                    throw new NullReferenceException("Cannot find instance of StateManager in the ASP.NET session.");
 49                }

 50            }
 
 51            ParseContext();
 52            if(sm != null)
 53            {
 54                PrepareStateManagerParamsDictionary(sm);
 55                sm.RestoreState();
 56            }

 57
 58            Process();
 59        }

 60
 61        /// <summary>
 62        /// method to do the real server side process for info tool.
 63        /// </summary>

 64        public override void Process()
 65        {
 66            //get pixel tolerance from url of client side.
 67            int pixelTolerance = System.Convert.ToInt32(HttpContext.Current.Request[PixelToleranceKey]);
 68            
 69            MapControlModel model = MapControlModel.GetModelFromSession();
 70            model.SetMapSize(MapAlias, MapWidth, MapHeight);
 71            
 72            //extract points from url of client side.
 73            System.Drawing.Point[]  points = ExtractPoints(DataString);
 74            
 75            //do searching and get results back
 76            MultiResultSetFeatureCollection mrfc = RetrieveInfo(points, pixelTolerance);
 77                        
 78            IEnumerator resultEnum = mrfc.GetEnumerator();
 79            
 80            //retrieve the selected feature from collection
 81            while(resultEnum.MoveNext())
 82            {
 83                IResultSetFeatureCollection irfc = (IResultSetFeatureCollection)resultEnum.Current;
 84                IFeatureEnumerator ftrEnum = irfc.GetFeatureEnumerator();
 85                
 86                while(ftrEnum.MoveNext())
 87                {
 88                    Feature ftr = (Feature)ftrEnum.Current;
 89                    //create a html table to display feature info and stream back to client side.
 90                    CreateInfoTable(ftr);        
 91                    irfc.Close();
 92                    mrfc.Clear();
 93                    break;
 94                }
    
 95                break;
 96            }
    
 97        }

 98
 99        /// <summary>
100        /// Creates html table to hold passed in feature info, and stream back to client.
101        /// </summary>
102        /// <param name="ftr">feature object</param>

103        private void CreateInfoTable(Feature ftr)
104        {
105            //create a table control and populat it with the column name/value(s) from the feature returned and
106            // and the name of the layer where the feature belong
107            System.Web.UI.WebControls.Table infoTable = new System.Web.UI.WebControls.Table();
108            //set table attribute/styles
109            infoTable.CellPadding = 4;            
110            infoTable.Font.Name = "Arial";
111            infoTable.Font.Size = new FontUnit(8);
112            infoTable.BorderWidth = 1;
113            //infoTable.BorderStyle = BorderStyle.Outset; 
114            
115            System.Drawing.Color backColor = Color.Bisque;
116
117            //add the first row, the layer name/value where the selected feature belongs 
118            TableRow r = new TableRow();
119            r.BackColor = backColor;
120
121            TableCell c = new TableCell();
122            c.Font.Bold = true;            
123            c.ForeColor = Color.Indigo;
124
125            c.Text = "Layer Name";            
126            r.Cells.Add(c);
127
128            c = new TableCell();
129
130            //the feature returned is from a resultset table whose name is got from appending _2
131            //to the real table name, so below is to get the real table name.
132            string alias = ftr.Table.Alias;
133            c.Text = alias.Substring(0, alias.Length-2);
134            c.Font.Bold = true;
135            r.Cells.Add(c);
136            
137            infoTable.Rows.Add(r);
138
139            foreach(Column col in ftr.Columns)
140            {
141                String upAlias = col.Alias.ToUpper();
142                //don't display obj, MI_Key or MI_Style columns
143                if(upAlias != "OBJ" && upAlias != "MI_STYLE" && upAlias != "MI_KEY")
144                {
145                    r = new TableRow();
146                    r.BackColor = backColor;
147
148                    r.Cells.Clear();
149                    c = new TableCell();
150                    c.Text = col.Alias;
151                    c.Font.Bold = true;
152                    c.ForeColor = Color.RoyalBlue;
153
154                    r.Cells.Add(c);
155                    c = new TableCell();
156                    c.Text = ftr[col.Alias].ToString();
157                    r.Cells.Add(c);
158                    infoTable.Rows.Add(r);
159                }

160            }

161
162            //stream the html table back to client
163            StringWriter sw = new StringWriter();
164            HtmlTextWriter hw = new HtmlTextWriter(sw);
165            infoTable.RenderControl(hw);
166            String strHTML = sw.ToString();
167            HttpContext.Current.Response.Output.Write(strHTML);
168        }

169
170        /// <summary>
171        /// Get a MultiFeatureCollection containing features in all layers falling into the tolerance of the point.
172        /// </summary>
173        /// <param name="points">points array</param>
174        /// <param name="pixelTolerance">pixel tolerance used when searching</param>
175        /// <returns>Returns a MultiResultSetFeatureCollection object</returns>

176        protected MultiResultSetFeatureCollection RetrieveInfo(Point[] points, int pixelTolerance) 
177        {
178            if(points.Length != 1)
179                return null;
180
181            MapControlModel model = MapControlModel.GetModelFromSession();
182            //get map object from map model
183            MapInfo.Mapping.Map map = model.GetMapObj(MapAlias);
184
185            if(map == nullreturn null;
186
187            //creat a layer filter to include normal visible layers for searching
188            IMapLayerFilter layerFilter = MapLayerFilterFactory.FilterForTools(
189                map, MapLayerFilterFactory.FilterByLayerType(LayerType.Normal), MapLayerFilterFactory.FilterVisibleLayers(true), 
190                "MapInfo.Tools.MapToolsDefault.SelectLayers"null);
191
192            ITableEnumerator tableEnum = map.Layers.GetTableEnumerator(layerFilter);
193            
194            //return if there is no valid layer to search
195            if(tableEnum == nullreturn null;
196
197            System.Drawing.Point center = points[0];
198            
199            //create a SearchInfo with a point and tolerance
200            SearchInfo si = MapInfo.Mapping.SearchInfoFactory.SearchNearest(map, center, pixelTolerance);
201            (si.SearchResultProcessor as ClosestSearchResultProcessor).Options = ClosestSearchOptions.StopAtFirstMatch;
202            //retrieve all columns
203            si.QueryDefinition.Columns = null;
204            
205            MapInfo.Geometry.Distance d = MapInfo.Mapping.SearchInfoFactory.ScreenToMapDistance(map, pixelTolerance);
206            (si.SearchResultProcessor as ClosestSearchResultProcessor).DistanceUnit=d.Unit;
207            (si.SearchResultProcessor as ClosestSearchResultProcessor).MaxDistance = d.Value;
208
209            
210            //do search
211            MultiResultSetFeatureCollection mrfc = MapInfo.Engine.Session.Current.Catalog.Search(tableEnum, si);
212            return mrfc;
213
214        }

215    }

216
217    /// <summary>
218    /// ZoomValue command to write current zoom value to client for display.
219    /// </summary>

220    [Serializable]
221    public class ZoomValue : MapInfo.WebControls.MapBaseCommand
222    {
223        /// <summary>
224        /// Constructor for ZoomValue class
225        /// </summary>

226        public ZoomValue()
227        {
228            Name = "ZoomValue";
229        }

230
231        /// <summary>
232        /// Override the Execute method in MapBasicCommand class to NOT save state, because
233        /// for this command, which does not change map state, so there is no need to save map state.
234        /// </summary>

235        public override void Execute()
236        {
237            
238            StateManager sm = StateManager.GetStateManagerFromSession();
239            if (sm == null
240            {
241                if(StateManager.IsManualState())
242                {
243                    throw new NullReferenceException("Cannot find instance of StateManager in the ASP.NET session.");
244                }

245            }
 
246            ParseContext();
247            if(sm != null)
248            {
249                PrepareStateManagerParamsDictionary(sm);
250                sm.RestoreState();
251            }

252
253            Process();
254        }

255
256        public override void Process()
257        {
258            MapControlModel model = MapControlModel.GetModelFromSession();
259            //get map object from map model
260            MapInfo.Mapping.Map map = model.GetMapObj(MapAlias);
261            MapInfo.Mapping.Map map2 = model.GetMapObj("Map2");
262            System.Drawing.Rectangle rect;
263            map2.DisplayTransform.ToDisplay(map.Bounds, out rect);
264            
265            HttpContext.Current.Response.Output.Write(rect.X);
266            HttpContext.Current.Response.Output.Write(',');
267            HttpContext.Current.Response.Output.Write(rect.Y);
268            HttpContext.Current.Response.Output.Write(',');
269            HttpContext.Current.Response.Output.Write(rect.Width);
270            HttpContext.Current.Response.Output.Write(',');
271            HttpContext.Current.Response.Output.Write(rect.Height);
289        }

290    }

291}

292

客户端JS代码:
 1//client info command to control client behavior for info tool.
 2function InfoCommand(name, interaction)
 3{
 4    if (arguments.length > 0{
 5        this.Init(name, interaction);
 6    }

 7}

 8InfoCommand.prototype = new MapCommand();
 9InfoCommand.prototype.constructor = InfoCommand;
10InfoCommand.superclass = MapCommand.prototype;
11InfoCommand.prototype.Execute = function()
12{
13    this.CreateUrl();
14    this.AddParamToUrl("PixelTolerance"this.pixelTolerance);
15    //create an XMLHttp obj to send request to server
16    var xmlHttp = CreateXMLHttp();
17    xmlHttp.open("GET"this.url, false);
18    xmlHttp.send(null);
19    //get response back
20    this.result = xmlHttp.responseText;
21    
22    var div = FindElement("Info");
23    if(div.style.visibility != "visible")
24        div.style.visibility = "visible";        
25    //display the response at client html
26    div.innerHTML = "<font size=2 face=Arial><b>Selected Feature Info:</b></font><p>" + this.result;
27
28}
;
29//function to update zoom label
30function getZoomValue()
31{
32    //create url to send to server, server command name is "ZoomValue"
33    var url = "MapController.ashx?Command=ZoomValue&Ran=" + Math.random();
34    var mapImage = document.getElementById("MapControl1_Image");                        
35    if (mapImage.mapAlias) 
36        url +=  "&MapAlias=" + mapImage.mapAlias;
37    var xmlHttp = CreateXMLHttp();
38    xmlHttp.open("GET", url, false);
39    xmlHttp.send(null);
40    var result = xmlHttp.responseText;        
41    var div = FindElement("ZoomValue");
42    div.innerHTML = "<font size=2 face=Arial><b>Zoom: <font color=Indigo>" + result + "</font></b></font>";
43    
44    var arr = new Array();
45    arr = result.split(',');
46    var left = 1*arr[0];
47    var top = 1*arr[1];
48    var width = 1*arr[2];
49    var height = 1*arr[3];
50    if (left < 0) left = 0;
51    if (top < 0) top = 0;
52    if (width > 232) width = 232;
53    if (height > 210) height = 210;
54    //alert(left+","+top+","+width+","+height);
55    myDrawFunction(left, top, width, height);
56}
;    
57
58
后台HTML文件代码:
 1<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="InfoToolWeb.WebForm1_temp" %>
 2<%@ Register TagPrefix="mapinfowebuiwebcontrols" Namespace="MapInfo.WebControls" Assembly="MapInfo.WebControls, Version=4.0.0.362, Culture=neutral, PublicKeyToken=0a9556cc66c0af57" %>
 3<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
 4<HTML xmlns:v="urn:schemas-microsoft-com:vml">
 5    <HEAD>
 6        <title>WebForm1</title>
 7        <meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
 8        <meta content="C#" name="CODE_LANGUAGE">
 9        <meta content="JavaScript" name="vs_defaultClientScript">
10        <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
11        <style>v\:* { BEHAVIOR: url(#default#VML) }
12        
</style>
13        <script src="wz_jsgraphics.js" type="text/javascript"></script>
14    </HEAD>
15    <body bgColor="#ffefd5" MS_POSITIONING="GridLayout">
16        <form id="Form1" method="post" runat="server">
17            <!-- inlcude javascript for info tool here -->
18            <script language="javascript" src="CustomCommand.js" type="text/javascript"></script>
19            <!-- zoom label used to display current zoom value ->
20            <DIV id="ZoomValue" style="DISPLAY: inline; Z-INDEX: 124; LEFT: 120px; WIDTH: 872px; POSITION: absolute; TOP: 88px; HEIGHT: 19px"
21                ms_positioning="FlowLayout"><STRONG><FONT face="Arial" size="2">Zoom:</FONT></STRONG></DIV>
22            <mapinfowebuiwebcontrols:mapcontrol id="MapControl1" style="Z-INDEX: 101; LEFT: 88px; POSITION: absolute; TOP: 128px"
23                runat="server" MapAlias="Map1" Height="600px" Width="600px"></mapinfowebuiwebcontrols:mapcontrol><mapinfowebuiwebcontrols:southnavigationtool id="SouthNavigationTool2" style="Z-INDEX: 102; LEFT: 640px; POSITION: absolute; TOP: 944px"
24                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:southnavigationtool><mapinfowebuiwebcontrols:northnavigationtool id="NorthNavigationTool2" style="Z-INDEX: 104; LEFT: 224px; POSITION: absolute; TOP: 112px"
25                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:northnavigationtool><mapinfowebuiwebcontrols:eastnavigationtool id="EastNavigationTool2" style="Z-INDEX: 105; LEFT: 912px; POSITION: absolute; TOP: 552px"
26                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:eastnavigationtool><mapinfowebuiwebcontrols:westnavigationtool id="WestNavigationTool2" style="Z-INDEX: 106; LEFT: 72px; POSITION: absolute; TOP: 280px"
27                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:westnavigationtool><mapinfowebuiwebcontrols:northeastnavigationtool id="NorthEastNavigationTool1" style="Z-INDEX: 108; LEFT: 840px; POSITION: absolute; TOP: 112px"
28                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:northeastnavigationtool><mapinfowebuiwebcontrols:southwestnavigationtool id="SouthWestNavigationTool1" style="Z-INDEX: 109; LEFT: 64px; POSITION: absolute; TOP: 616px"
29                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:southwestnavigationtool><mapinfowebuiwebcontrols:southeastnavigationtool id="SouthEastNavigationTool1" style="Z-INDEX: 110; LEFT: 952px; POSITION: absolute; TOP: 848px"
30                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:southeastnavigationtool><mapinfowebuiwebcontrols:northwestnavigationtool id="NorthWestNavigationTool1" style="Z-INDEX: 111; LEFT: 72px; POSITION: absolute; TOP: 112px"
31                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:northwestnavigationtool><mapinfowebuiwebcontrols:zoombartool id="ZoomBarTool1" style="Z-INDEX: 112; LEFT: 24px; POSITION: absolute; TOP: 216px"
32                runat="server" Height="8px" MapControlID="MapControl1" ZoomLevel="12500"></mapinfowebuiwebcontrols:zoombartool><mapinfowebuiwebcontrols:zoombartool id="ZoomBarTool2" style="Z-INDEX: 113; LEFT: 24px; POSITION: absolute; TOP: 240px"
33                runat="server" Height="8px" MapControlID="MapControl1" ZoomLevel="6500"></mapinfowebuiwebcontrols:zoombartool><mapinfowebuiwebcontrols:zoombartool id="ZoomBarTool3" style="Z-INDEX: 114; LEFT: 24px; POSITION: absolute; TOP: 264px"
34                runat="server" Height="8px" MapControlID="MapControl1" ZoomLevel="3550"></mapinfowebuiwebcontrols:zoombartool><mapinfowebuiwebcontrols:zoombartool id="ZoomBarTool4" style="Z-INDEX: 115; LEFT: 24px; POSITION: absolute; TOP: 288px"
35                runat="server" MapControlID="MapControl1" ZoomLevel="1500"></mapinfowebuiwebcontrols:zoombartool><mapinfowebuiwebcontrols:zoombartool id="ZoomBarTool5" style="Z-INDEX: 116; LEFT: 24px; POSITION: absolute; TOP: 312px"
36                runat="server" MapControlID="MapControl1" ZoomLevel="500"></mapinfowebuiwebcontrols:zoombartool><asp:image id="Image1" style="Z-INDEX: 117; LEFT: 32px; POSITION: absolute; TOP: 336px" runat="server"
37                ImageUrl="/MapXTremeWebResources 6_5/ZoomInToolControlActive.gif"></asp:image><asp:image id="Image2" style="Z-INDEX: 118; LEFT: 32px; POSITION: absolute; TOP: 192px" runat="server"
38                ImageUrl="/MapXTremeWebResources 6_5/ZoomOutToolControlActive.gif"></asp:image>
39            <div id="Info" style="Z-INDEX: 119; LEFT: 712px; VISIBILITY: hidden; POSITION: absolute; TOP: 16px">Div&nbsp;element 
40                to display selected feature information in html table.</div>
41            <mapinfowebuiwebcontrols:pantool id="PanTool1" style="Z-INDEX: 120; LEFT: 984px; POSITION: absolute; TOP: 464px"
42                runat="server" MapControlID="MapControl1" ClientCommand="MapCommand"></mapinfowebuiwebcontrols:pantool><mapinfowebuiwebcontrols:zoomintool id="ZoomInTool1" style="Z-INDEX: 121; LEFT: 904px; POSITION: absolute; TOP: 464px"
43                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:zoomintool><mapinfowebuiwebcontrols:zoomouttool id="ZoomOutTool1" style="Z-INDEX: 122; LEFT: 944px; POSITION: absolute; TOP: 464px"
44                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:zoomouttool><mapinfowebuiwebcontrols:centertool id="CenterTool1" style="Z-INDEX: 123; LEFT: 1024px; POSITION: absolute; TOP: 464px"
45                runat="server" MapControlID="MapControl1"></mapinfowebuiwebcontrols:centertool><mapinfowebuiwebcontrols:pointselectiontool id="InfoWebTool1" style="Z-INDEX: 125; LEFT: 1072px; POSITION: absolute; TOP: 464px"
46                runat="server" MapControlID="MapControl1" ClientInteraction="ClickInteraction" ActiveImageUrl="/MapXtremeWebResources 6_5/InfoToolControlActive.gif" InactiveImageUrl="/MapXtremeWebResources 6_5/InfoToolControlInActive.gif"
47                CursorImageUrl="/MapXtremeWebResources 6_5/MapInfoWebInfo.cur" Command="Info" ClientCommand="InfoCommand"></mapinfowebuiwebcontrols:pointselectiontool><asp:label id="Label1" style="Z-INDEX: 107; LEFT: 72px; POSITION: absolute; TOP: 16px" runat="server"
48                Height="48px" Width="712px" Font-Size="X-Large" ForeColor="Navy" BorderColor="MediumTurquoise">InfoTool Web Sample </asp:label><asp:textbox id="TextBox1" style="Z-INDEX: 103; LEFT: 64px; POSITION: absolute; TOP: 64px" runat="server"
49                Height="8px" Width="806px" BackColor="DarkBlue"></asp:textbox><mapinfowebuiwebcontrols:rectangleselectiontool id="RectangleSelectionTool1" style="Z-INDEX: 126; LEFT: 1104px; POSITION: absolute; TOP: 464px"
50                runat="server" MapControlID="MapControl1" Command="RectangleSelection" ClientCommand="MapCommand" Active="True"></mapinfowebuiwebcontrols:rectangleselectiontool>
51            <div id="myCanvas" style="LEFT:896px;WIDTH:230px;POSITION:absolute;TOP:120px;HEIGHT:230px"><IMG src="file:///C:\Program Files\MapInfo\MapXtreme\6.5\Samples\Web\Features\InfoToolWeb\cs\eyemap.GIF"
52                    height="230" width="230"></div>
53            <script src="drawfunction.js" type="text/javascript"></script>
54            <INPUT style="Z-INDEX: 128; LEFT: 896px; POSITION: absolute; TOP: 416px" type="button"
55                value="Button" onclick="myDrawFunction()">
56            <script language="javascript" type="text/javascript">
57                    //first time when page loads, at this point, maybe the image is already loaded, so
58                    //alway call getZoomValue when the page loads first time.
59                    getZoomValue();
60                    
61                    //hook up map image onload event with getZoomValue method.
62                    var mapimage = document.getElementById("MapControl1_Image");            
63                    mapimage.onload = getZoomValue;                        
64            </script>
65        </form>
66    </body>
67</HTML>
68

Feedback

# re: MapInfo MapXtreme 2005 WebGIS上实现简单鹰眼设计!  回复  更多评论   

2006-10-17 14:33 by 李珍宝
借鉴你的思路。

# re: MapInfo MapXtreme 2005 WebGIS上实现简单鹰眼设计!  回复  更多评论   

2006-10-19 11:58 by DELL网站
好文,学习中...

# re: MapInfo MapXtreme 2005 WebGIS上实现简单鹰眼设计!  回复  更多评论   

2007-03-29 10:53 by Aaron.Lee
<script src="drawfunction.js" type="text/javascript"></script>
这个是最核心的代码,但是没有贴出来啊

# re: MapInfo MapXtreme 2005 WebGIS上实现简单鹰眼设计!  回复  更多评论   

2007-04-27 15:45 by ff
太保守了把~~·

<script src="drawfunction.js" type="text/javascript"></script>
这个是最核心的代码,但是没有贴出来啊

# re: MapInfo MapXtreme 2005 WebGIS上实现简单鹰眼设计!  回复  更多评论   

2007-07-15 21:48 by ss
这是自带的范例吧

# re: MapInfo MapXtreme 2005 WebGIS上实现简单鹰眼设计!  回复  更多评论   

2007-10-30 16:19 by 辅导
没有什么好说的了

# re: MapInfo MapXtreme 2005 WebGIS上实现简单鹰眼设计!  回复  更多评论   

2008-07-27 18:43 by sweet
var mapimage = document.getElementById("MapControl1_Image");
mapimage.onload = getZoomValue;
onload事件 pan(平移工具) 并不捕获,当使用pan 工具时,没响应
望解决
只有注册用户登录后才能发表评论。